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

Commit 9680cfae authored by Yi Jin's avatar Yi Jin
Browse files

Implement procstats dumpsys section

Bug: 65690183
Test: tested manually using incident-report tool
Change-Id: I0c34e411dba8faf9f311c78701ac8f6bec824277
parent f850cd8f
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 android.util.proto;

import android.util.AggStats;

/**
 * This class contains a list of helper functions to write common proto in
 * //frameworks/base/core/proto/android/base directory
 */
public class ProtoUtils {

    /**
     * Dump AggStats to ProtoOutputStream
     * @hide
     */
    public static void toAggStatsProto(ProtoOutputStream proto, long fieldId,
            long min, long average, long max) {
        final long aggStatsToken = proto.start(fieldId);
        proto.write(AggStats.MIN, min);
        proto.write(AggStats.AVERAGE, average);
        proto.write(AggStats.MAX, max);
        proto.end(aggStatsToken);
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

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

@@ -66,6 +67,8 @@ public final class DumpUtils {
            "cch-activity", "cch-aclient", "cch-empty"
    };

    // State enum is defined in frameworks/base/core/proto/android/service/procstats.proto
    // Update states must sync enum definition as well, the ordering must not be changed.
    static final String[] ADJ_SCREEN_TAGS = new String[] {
            "0", "1"
    };
@@ -177,6 +180,13 @@ public final class DumpUtils {
        printArrayEntry(pw, STATE_TAGS,  state, 1);
    }

    public static void printProcStateTagProto(ProtoOutputStream proto, long screenId, long memId,
            long stateId, int state) {
        state = printProto(proto, screenId, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD * STATE_COUNT);
        state = printProto(proto, memId, ADJ_MEM_TAGS, state, STATE_COUNT);
        printProto(proto, stateId, STATE_TAGS, state, 1);
    }

    public static void printAdjTag(PrintWriter pw, int state) {
        state = printArrayEntry(pw, ADJ_SCREEN_TAGS,  state, ADJ_SCREEN_MOD);
        printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
@@ -352,6 +362,15 @@ public final class DumpUtils {
        return value - index*mod;
    }

    public static int printProto(ProtoOutputStream proto, long fieldId, String[] array, int value, int mod) {
        int index = value/mod;
        if (index >= 0 && index < array.length) {
            // Valid state enum number starts at 1, 0 stands for unknown.
            proto.write(fieldId, index + 1);
        } // else enum default is always zero in proto3
        return value - index*mod;
    }

    public static String collapseString(String pkgName, String itemName) {
        if (itemName.startsWith(pkgName)) {
            final int ITEMLEN = itemName.length();
+81 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.os.Parcelable;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.service.pm.PackageProto;
import android.service.procstats.ProcessStatsProto;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -29,6 +31,8 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;

import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.app.procstats.ProcessStats.PackageState;
@@ -69,6 +73,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public final class ProcessState {
@@ -1157,6 +1164,7 @@ public final class ProcessState {
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(128);
        sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
@@ -1167,4 +1175,77 @@ public final class ProcessState {
        sb.append("}");
        return sb.toString();
    }

    public void toProto(ProtoOutputStream proto, String procName, int uid, long now) {
        proto.write(ProcessStatsProto.PROCESS, procName);
        proto.write(ProcessStatsProto.UID, uid);
        if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
            final long killToken = proto.start(ProcessStatsProto.KILL);
            proto.write(ProcessStatsProto.Kill.WAKES, mNumExcessiveWake);
            proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
            proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
                    mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
            proto.end(killToken);
        }

        // Group proc stats by type (screen state + mem state + process state)
        Map<Integer, Long> durationByState = new HashMap<>();
        boolean didCurState = false;
        for (int i=0; i<mDurations.getKeyCount(); i++) {
            final int key = mDurations.getKeyAt(i);
            final int type = SparseMappingTable.getIdFromKey(key);
            long time = mDurations.getValue(key);
            if (mCurState == type) {
                didCurState = true;
                time += now - mStartTime;
            }
            durationByState.put(type, time);
        }
        if (!didCurState && mCurState != STATE_NOTHING) {
            durationByState.put(mCurState, now - mStartTime);
        }

        for (int i=0; i<mPssTable.getKeyCount(); i++) {
            final int key = mPssTable.getKeyAt(i);
            final int type = SparseMappingTable.getIdFromKey(key);
            if (!durationByState.containsKey(type)) {
                // state without duration should not have stats!
                continue;
            }
            final long stateToken = proto.start(ProcessStatsProto.STATES);
            DumpUtils.printProcStateTagProto(proto,
                    ProcessStatsProto.State.SCREEN_STATE,
                    ProcessStatsProto.State.MEMORY_STATE,
                    ProcessStatsProto.State.PROCESS_STATE,
                    type);

            long duration = durationByState.get(type);
            durationByState.remove(type); // remove the key since it is already being dumped.
            proto.write(ProcessStatsProto.State.DURATION_MS, duration);

            proto.write(ProcessStatsProto.State.SAMPLE_SIZE, mPssTable.getValue(key, PSS_SAMPLE_COUNT));
            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.PSS,
                    mPssTable.getValue(key, PSS_MINIMUM),
                    mPssTable.getValue(key, PSS_AVERAGE),
                    mPssTable.getValue(key, PSS_MAXIMUM));
            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.USS,
                    mPssTable.getValue(key, PSS_USS_MINIMUM),
                    mPssTable.getValue(key, PSS_USS_AVERAGE),
                    mPssTable.getValue(key, PSS_USS_MAXIMUM));

            proto.end(stateToken);
        }

        for (Map.Entry<Integer, Long> entry : durationByState.entrySet()) {
            final long stateToken = proto.start(ProcessStatsProto.STATES);
            DumpUtils.printProcStateTagProto(proto,
                    ProcessStatsProto.State.SCREEN_STATE,
                    ProcessStatsProto.State.MEMORY_STATE,
                    ProcessStatsProto.State.PROCESS_STATE,
                    entry.getKey());
            proto.write(ProcessStatsProto.State.DURATION_MS, entry.getValue());
            proto.end(stateToken);
        }
    }
}
+42 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Parcelable;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.service.procstats.ProcessStatsSectionProto;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -30,6 +31,7 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.DurationsTable;
@@ -1706,6 +1708,46 @@ public final class ProcessStats implements Parcelable {
        }
    }

    public void toProto(ProtoOutputStream proto, long now) {
        final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();

        proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
        proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
                mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
        proto.write(ProcessStatsSectionProto.START_UPTIME_MS, mTimePeriodStartUptime);
        proto.write(ProcessStatsSectionProto.END_UPTIME_MS, mTimePeriodEndUptime);
        proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime);
        proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss);
        boolean partial = true;
        if ((mFlags&FLAG_SHUTDOWN) != 0) {
            proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN);
            partial = false;
        }
        if ((mFlags&FLAG_SYSPROPS) != 0) {
            proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS);
            partial = false;
        }
        if ((mFlags&FLAG_COMPLETE) != 0) {
            proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE);
            partial = false;
        }
        if (partial) {
            proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL);
        }

        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
        for (int ip=0; ip<procMap.size(); ip++) {
            String procName = procMap.keyAt(ip);
            SparseArray<ProcessState> uids = procMap.valueAt(ip);
            for (int iu=0; iu<uids.size(); iu++) {
                final int uid = uids.keyAt(iu);
                final ProcessState procState = uids.valueAt(iu);
                final long processStateToken = proto.start(ProcessStatsSectionProto.PROCESS_STATS);
                procState.toProto(proto, procName, uid, now);
                proto.end(processStateToken);
            }
        }
    }

    final public static class ProcessStateHolder {
        public final int appVersion;
+6 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import "frameworks/base/core/proto/android/service/notification.proto";
import "frameworks/base/core/proto/android/service/package.proto";
import "frameworks/base/core/proto/android/service/power.proto";
import "frameworks/base/core/proto/android/service/print.proto";
import "frameworks/base/core/proto/android/service/procstats.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
@@ -96,4 +97,9 @@ message IncidentProto {
    android.service.pm.PackageServiceDumpProto package = 3008;
    android.service.power.PowerServiceDumpProto power = 3009;
    android.service.print.PrintServiceDumpProto print = 3010;

    android.service.procstats.ProcessStatsServiceDumpProto procstats = 3011 [
        (section).type = SECTION_DUMPSYS,
        (section).args = "procstats --proto"
    ];
}
Loading