| /* |
| * Copyright (C) 2013 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.content.ComponentName; |
| import android.os.Debug; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import android.os.UserHandle; |
| import android.service.procstats.ProcessStatsPackageProto; |
| import android.service.procstats.ProcessStatsSectionProto; |
| import android.text.format.DateFormat; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.DebugUtils; |
| import android.util.LongSparseArray; |
| import android.util.Slog; |
| import android.util.SparseArray; |
| import android.util.TimeUtils; |
| import android.util.proto.ProtoOutputStream; |
| |
| import com.android.internal.app.ProcessMap; |
| |
| import dalvik.system.VMRuntime; |
| |
| import java.io.BufferedReader; |
| import java.io.FileReader; |
| 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.Objects; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public final class ProcessStats implements Parcelable { |
| public static final String TAG = "ProcessStats"; |
| static final boolean DEBUG = false; |
| static final boolean DEBUG_PARCEL = false; |
| |
| public static final String SERVICE_NAME = "procstats"; |
| |
| // How often the service commits its data, giving the minimum batching |
| // that is done. |
| public static long COMMIT_PERIOD = 3*60*60*1000; // Commit current stats every 3 hours |
| |
| // Minimum uptime period before committing. If the COMMIT_PERIOD has elapsed but |
| // the total uptime has not exceeded this amount, then the commit will be held until |
| // it is reached. |
| public static long COMMIT_UPTIME_PERIOD = 60*60*1000; // Must have at least 1 hour elapsed |
| |
| public static final int STATE_NOTHING = -1; |
| public static final int STATE_PERSISTENT = 0; |
| public static final int STATE_TOP = 1; |
| public static final int STATE_IMPORTANT_FOREGROUND = 2; |
| public static final int STATE_IMPORTANT_BACKGROUND = 3; |
| public static final int STATE_BACKUP = 4; |
| public static final int STATE_SERVICE = 5; |
| public static final int STATE_SERVICE_RESTARTING = 6; |
| public static final int STATE_RECEIVER = 7; |
| public static final int STATE_HEAVY_WEIGHT = 8; |
| public static final int STATE_HOME = 9; |
| public static final int STATE_LAST_ACTIVITY = 10; |
| public static final int STATE_CACHED_ACTIVITY = 11; |
| public static final int STATE_CACHED_ACTIVITY_CLIENT = 12; |
| public static final int STATE_CACHED_EMPTY = 13; |
| public static final int STATE_COUNT = STATE_CACHED_EMPTY+1; |
| |
| public static final int PSS_SAMPLE_COUNT = 0; |
| public static final int PSS_MINIMUM = 1; |
| public static final int PSS_AVERAGE = 2; |
| public static final int PSS_MAXIMUM = 3; |
| public static final int PSS_USS_MINIMUM = 4; |
| public static final int PSS_USS_AVERAGE = 5; |
| public static final int PSS_USS_MAXIMUM = 6; |
| public static final int PSS_RSS_MINIMUM = 7; |
| public static final int PSS_RSS_AVERAGE = 8; |
| public static final int PSS_RSS_MAXIMUM = 9; |
| public static final int PSS_COUNT = PSS_RSS_MAXIMUM+1; |
| |
| public static final int SYS_MEM_USAGE_SAMPLE_COUNT = 0; |
| public static final int SYS_MEM_USAGE_CACHED_MINIMUM = 1; |
| public static final int SYS_MEM_USAGE_CACHED_AVERAGE = 2; |
| public static final int SYS_MEM_USAGE_CACHED_MAXIMUM = 3; |
| public static final int SYS_MEM_USAGE_FREE_MINIMUM = 4; |
| public static final int SYS_MEM_USAGE_FREE_AVERAGE = 5; |
| public static final int SYS_MEM_USAGE_FREE_MAXIMUM = 6; |
| public static final int SYS_MEM_USAGE_ZRAM_MINIMUM = 7; |
| public static final int SYS_MEM_USAGE_ZRAM_AVERAGE = 8; |
| public static final int SYS_MEM_USAGE_ZRAM_MAXIMUM = 9; |
| public static final int SYS_MEM_USAGE_KERNEL_MINIMUM = 10; |
| public static final int SYS_MEM_USAGE_KERNEL_AVERAGE = 11; |
| public static final int SYS_MEM_USAGE_KERNEL_MAXIMUM = 12; |
| public static final int SYS_MEM_USAGE_NATIVE_MINIMUM = 13; |
| public static final int SYS_MEM_USAGE_NATIVE_AVERAGE = 14; |
| public static final int SYS_MEM_USAGE_NATIVE_MAXIMUM = 15; |
| public static final int SYS_MEM_USAGE_COUNT = SYS_MEM_USAGE_NATIVE_MAXIMUM+1; |
| |
| public static final int ADJ_NOTHING = -1; |
| public static final int ADJ_MEM_FACTOR_NORMAL = 0; |
| public static final int ADJ_MEM_FACTOR_MODERATE = 1; |
| public static final int ADJ_MEM_FACTOR_LOW = 2; |
| public static final int ADJ_MEM_FACTOR_CRITICAL = 3; |
| public static final int ADJ_MEM_FACTOR_COUNT = ADJ_MEM_FACTOR_CRITICAL+1; |
| public static final int ADJ_SCREEN_MOD = ADJ_MEM_FACTOR_COUNT; |
| public static final int ADJ_SCREEN_OFF = 0; |
| public static final int ADJ_SCREEN_ON = ADJ_SCREEN_MOD; |
| public static final int ADJ_COUNT = ADJ_SCREEN_ON*2; |
| |
| public static final int FLAG_COMPLETE = 1<<0; |
| public static final int FLAG_SHUTDOWN = 1<<1; |
| public static final int FLAG_SYSPROPS = 1<<2; |
| |
| public static final int ADD_PSS_INTERNAL_SINGLE = 0; |
| public static final int ADD_PSS_INTERNAL_ALL_MEM = 1; |
| public static final int ADD_PSS_INTERNAL_ALL_POLL = 2; |
| public static final int ADD_PSS_EXTERNAL = 3; |
| public static final int ADD_PSS_EXTERNAL_SLOW = 4; |
| |
| public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, |
| ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL }; |
| |
| public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON }; |
| |
| public static final int[] NON_CACHED_PROC_STATES = new int[] { |
| STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND, |
| STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, |
| STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HEAVY_WEIGHT |
| }; |
| |
| public static final int[] BACKGROUND_PROC_STATES = new int[] { |
| STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, |
| STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER |
| }; |
| |
| public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, |
| STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, |
| STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, |
| STATE_HEAVY_WEIGHT, STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY, |
| STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY |
| }; |
| |
| // Should report process stats. |
| public static final int REPORT_PROC_STATS = 0x01; |
| // Should report package process stats. |
| public static final int REPORT_PKG_PROC_STATS = 0x02; |
| // Should report package service stats. |
| public static final int REPORT_PKG_SVC_STATS = 0x04; |
| // Should report package association stats. |
| public static final int REPORT_PKG_ASC_STATS = 0x08; |
| // Should report package stats. |
| public static final int REPORT_PKG_STATS = 0x0E; |
| // Should report all stats. |
| public static final int REPORT_ALL = 0x0F; |
| |
| 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}; |
| public static final String[] OPTIONS_STR = |
| {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"}; |
| |
| // Current version of the parcel format. |
| private static final int PARCEL_VERSION = 35; |
| // In-memory Parcel magic number, used to detect attempts to unmarshall bad data |
| private static final int MAGIC = 0x50535454; |
| |
| public String mReadError; |
| public String mTimePeriodStartClockStr; |
| public int mFlags; |
| |
| public final ProcessMap<LongSparseArray<PackageState>> mPackages = new ProcessMap<>(); |
| public final ProcessMap<ProcessState> mProcesses = new ProcessMap<>(); |
| |
| public final ArrayList<AssociationState.SourceState> mTrackingAssociations = new ArrayList<>(); |
| |
| public final long[] mMemFactorDurations = new long[ADJ_COUNT]; |
| public int mMemFactor = STATE_NOTHING; |
| public long mStartTime; |
| |
| public long mTimePeriodStartClock; |
| public long mTimePeriodStartRealtime; |
| public long mTimePeriodEndRealtime; |
| public long mTimePeriodStartUptime; |
| public long mTimePeriodEndUptime; |
| String mRuntime; |
| boolean mRunning; |
| |
| boolean mHasSwappedOutPss; |
| |
| // Count and total time expended doing "quick" single pss computations for internal use. |
| public long mInternalSinglePssCount; |
| public long mInternalSinglePssTime; |
| |
| // Count and total time expended doing "quick" all mem pss computations for internal use. |
| public long mInternalAllMemPssCount; |
| public long mInternalAllMemPssTime; |
| |
| // Count and total time expended doing "quick" all poll pss computations for internal use. |
| public long mInternalAllPollPssCount; |
| public long mInternalAllPollPssTime; |
| |
| // Count and total time expended doing "quick" pss computations due to external requests. |
| public long mExternalPssCount; |
| public long mExternalPssTime; |
| |
| // Count and total time expended doing full/slow pss computations due to external requests. |
| public long mExternalSlowPssCount; |
| public long mExternalSlowPssTime; |
| |
| public final SparseMappingTable mTableData = new SparseMappingTable(); |
| |
| public final long[] mSysMemUsageArgs = new long[SYS_MEM_USAGE_COUNT]; |
| public final SysMemUsageTable mSysMemUsage = new SysMemUsageTable(mTableData); |
| |
| // For writing parcels. |
| ArrayMap<String, Integer> mCommonStringToIndex; |
| |
| // For reading parcels. |
| ArrayList<String> mIndexToCommonString; |
| |
| private static final Pattern sPageTypeRegex = Pattern.compile( |
| "^Node\\s+(\\d+),.*. type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$"); |
| private final ArrayList<Integer> mPageTypeZones = new ArrayList<Integer>(); |
| private final ArrayList<String> mPageTypeLabels = new ArrayList<String>(); |
| private final ArrayList<int[]> mPageTypeSizes = new ArrayList<int[]>(); |
| |
| public ProcessStats(boolean running) { |
| mRunning = running; |
| reset(); |
| if (running) { |
| // If we are actively running, we need to determine whether the system is |
| // collecting swap pss data. |
| Debug.MemoryInfo info = new Debug.MemoryInfo(); |
| Debug.getMemoryInfo(android.os.Process.myPid(), info); |
| mHasSwappedOutPss = info.hasSwappedOutPss(); |
| } |
| } |
| |
| public ProcessStats(Parcel in) { |
| reset(); |
| readFromParcel(in); |
| } |
| |
| public void add(ProcessStats other) { |
| ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| other.mPackages.getMap(); |
| for (int ip=0; ip<pkgMap.size(); ip++) { |
| final String pkgName = pkgMap.keyAt(ip); |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| for (int iu=0; iu<uids.size(); iu++) { |
| final int uid = uids.keyAt(iu); |
| final LongSparseArray<PackageState> versions = uids.valueAt(iu); |
| for (int iv=0; iv<versions.size(); iv++) { |
| final long vers = versions.keyAt(iv); |
| final PackageState otherState = versions.valueAt(iv); |
| final int NPROCS = otherState.mProcesses.size(); |
| final int NSRVS = otherState.mServices.size(); |
| final int NASCS = otherState.mAssociations.size(); |
| for (int iproc=0; iproc<NPROCS; iproc++) { |
| ProcessState otherProc = otherState.mProcesses.valueAt(iproc); |
| if (otherProc.getCommonProcess() != otherProc) { |
| if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid |
| + " vers " + vers + " proc " + otherProc.getName()); |
| ProcessState thisProc = getProcessStateLocked(pkgName, uid, vers, |
| otherProc.getName()); |
| if (thisProc.getCommonProcess() == thisProc) { |
| if (DEBUG) Slog.d(TAG, "Existing process is single-package, splitting"); |
| thisProc.setMultiPackage(true); |
| long now = SystemClock.uptimeMillis(); |
| final PackageState pkgState = getPackageStateLocked(pkgName, uid, |
| vers); |
| thisProc = thisProc.clone(now); |
| pkgState.mProcesses.put(thisProc.getName(), thisProc); |
| } |
| thisProc.add(otherProc); |
| } |
| } |
| for (int isvc=0; isvc<NSRVS; isvc++) { |
| ServiceState otherSvc = otherState.mServices.valueAt(isvc); |
| if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid |
| + " service " + otherSvc.getName()); |
| ServiceState thisSvc = getServiceStateLocked(pkgName, uid, vers, |
| otherSvc.getProcessName(), otherSvc.getName()); |
| thisSvc.add(otherSvc); |
| } |
| for (int iasc=0; iasc<NASCS; iasc++) { |
| AssociationState otherAsc = otherState.mAssociations.valueAt(iasc); |
| if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid |
| + " association " + otherAsc.getName()); |
| AssociationState thisAsc = getAssociationStateLocked(pkgName, uid, vers, |
| otherAsc.getProcessName(), otherAsc.getName()); |
| thisAsc.add(otherAsc); |
| } |
| } |
| } |
| } |
| |
| ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap(); |
| for (int ip=0; ip<procMap.size(); ip++) { |
| SparseArray<ProcessState> uids = procMap.valueAt(ip); |
| for (int iu=0; iu<uids.size(); iu++) { |
| int uid = uids.keyAt(iu); |
| ProcessState otherProc = uids.valueAt(iu); |
| final String name = otherProc.getName(); |
| final String pkg = otherProc.getPackage(); |
| final long vers = otherProc.getVersion(); |
| ProcessState thisProc = mProcesses.get(name, uid); |
| if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + name); |
| if (thisProc == null) { |
| if (DEBUG) Slog.d(TAG, "Creating new process!"); |
| thisProc = new ProcessState(this, pkg, uid, vers, name); |
| mProcesses.put(name, uid, thisProc); |
| PackageState thisState = getPackageStateLocked(pkg, uid, vers); |
| if (!thisState.mProcesses.containsKey(name)) { |
| thisState.mProcesses.put(name, thisProc); |
| } |
| } |
| thisProc.add(otherProc); |
| } |
| } |
| |
| for (int i=0; i<ADJ_COUNT; i++) { |
| if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by " |
| + other.mMemFactorDurations[i] + " from " |
| + mMemFactorDurations[i]); |
| mMemFactorDurations[i] += other.mMemFactorDurations[i]; |
| } |
| |
| mSysMemUsage.mergeStats(other.mSysMemUsage); |
| |
| if (other.mTimePeriodStartClock < mTimePeriodStartClock) { |
| mTimePeriodStartClock = other.mTimePeriodStartClock; |
| mTimePeriodStartClockStr = other.mTimePeriodStartClockStr; |
| } |
| mTimePeriodEndRealtime += other.mTimePeriodEndRealtime - other.mTimePeriodStartRealtime; |
| mTimePeriodEndUptime += other.mTimePeriodEndUptime - other.mTimePeriodStartUptime; |
| |
| mInternalSinglePssCount += other.mInternalSinglePssCount; |
| mInternalSinglePssTime += other.mInternalSinglePssTime; |
| mInternalAllMemPssCount += other.mInternalAllMemPssCount; |
| mInternalAllMemPssTime += other.mInternalAllMemPssTime; |
| mInternalAllPollPssCount += other.mInternalAllPollPssCount; |
| mInternalAllPollPssTime += other.mInternalAllPollPssTime; |
| mExternalPssCount += other.mExternalPssCount; |
| mExternalPssTime += other.mExternalPssTime; |
| mExternalSlowPssCount += other.mExternalSlowPssCount; |
| mExternalSlowPssTime += other.mExternalSlowPssTime; |
| |
| mHasSwappedOutPss |= other.mHasSwappedOutPss; |
| } |
| |
| public void addSysMemUsage(long cachedMem, long freeMem, long zramMem, long kernelMem, |
| long nativeMem) { |
| if (mMemFactor != STATE_NOTHING) { |
| int state = mMemFactor * STATE_COUNT; |
| mSysMemUsageArgs[SYS_MEM_USAGE_SAMPLE_COUNT] = 1; |
| for (int i=0; i<3; i++) { |
| mSysMemUsageArgs[SYS_MEM_USAGE_CACHED_MINIMUM + i] = cachedMem; |
| mSysMemUsageArgs[SYS_MEM_USAGE_FREE_MINIMUM + i] = freeMem; |
| mSysMemUsageArgs[SYS_MEM_USAGE_ZRAM_MINIMUM + i] = zramMem; |
| mSysMemUsageArgs[SYS_MEM_USAGE_KERNEL_MINIMUM + i] = kernelMem; |
| mSysMemUsageArgs[SYS_MEM_USAGE_NATIVE_MINIMUM + i] = nativeMem; |
| } |
| mSysMemUsage.mergeStats(state, mSysMemUsageArgs, 0); |
| } |
| } |
| |
| public static final Parcelable.Creator<ProcessStats> CREATOR |
| = new Parcelable.Creator<ProcessStats>() { |
| public ProcessStats createFromParcel(Parcel in) { |
| return new ProcessStats(in); |
| } |
| |
| public ProcessStats[] newArray(int size) { |
| return new ProcessStats[size]; |
| } |
| }; |
| |
| public void computeTotalMemoryUse(TotalMemoryUseCollection data, long now) { |
| data.totalTime = 0; |
| for (int i=0; i<STATE_COUNT; i++) { |
| data.processStateWeight[i] = 0; |
| data.processStatePss[i] = 0; |
| data.processStateTime[i] = 0; |
| data.processStateSamples[i] = 0; |
| } |
| for (int i=0; i<SYS_MEM_USAGE_COUNT; i++) { |
| data.sysMemUsage[i] = 0; |
| } |
| data.sysMemCachedWeight = 0; |
| data.sysMemFreeWeight = 0; |
| data.sysMemZRamWeight = 0; |
| data.sysMemKernelWeight = 0; |
| data.sysMemNativeWeight = 0; |
| data.sysMemSamples = 0; |
| final long[] totalMemUsage = mSysMemUsage.getTotalMemUsage(); |
| for (int is=0; is<data.screenStates.length; is++) { |
| for (int im=0; im<data.memStates.length; im++) { |
| int memBucket = data.screenStates[is] + data.memStates[im]; |
| int stateBucket = memBucket * STATE_COUNT; |
| long memTime = mMemFactorDurations[memBucket]; |
| if (mMemFactor == memBucket) { |
| memTime += now - mStartTime; |
| } |
| data.totalTime += memTime; |
| final int sysKey = mSysMemUsage.getKey((byte)stateBucket); |
| long[] longs = totalMemUsage; |
| int idx = 0; |
| if (sysKey != SparseMappingTable.INVALID_KEY) { |
| final long[] tmpLongs = mSysMemUsage.getArrayForKey(sysKey); |
| final int tmpIndex = SparseMappingTable.getIndexFromKey(sysKey); |
| if (tmpLongs[tmpIndex+SYS_MEM_USAGE_SAMPLE_COUNT] >= 3) { |
| SysMemUsageTable.mergeSysMemUsage(data.sysMemUsage, 0, longs, idx); |
| longs = tmpLongs; |
| idx = tmpIndex; |
| } |
| } |
| data.sysMemCachedWeight += longs[idx+SYS_MEM_USAGE_CACHED_AVERAGE] |
| * (double)memTime; |
| data.sysMemFreeWeight += longs[idx+SYS_MEM_USAGE_FREE_AVERAGE] |
| * (double)memTime; |
| data.sysMemZRamWeight += longs[idx + SYS_MEM_USAGE_ZRAM_AVERAGE] |
| * (double) memTime; |
| data.sysMemKernelWeight += longs[idx+SYS_MEM_USAGE_KERNEL_AVERAGE] |
| * (double)memTime; |
| data.sysMemNativeWeight += longs[idx+SYS_MEM_USAGE_NATIVE_AVERAGE] |
| * (double)memTime; |
| data.sysMemSamples += longs[idx+SYS_MEM_USAGE_SAMPLE_COUNT]; |
| } |
| } |
| data.hasSwappedOutPss = mHasSwappedOutPss; |
| ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); |
| for (int iproc=0; iproc<procMap.size(); iproc++) { |
| SparseArray<ProcessState> uids = procMap.valueAt(iproc); |
| for (int iu=0; iu<uids.size(); iu++) { |
| final ProcessState proc = uids.valueAt(iu); |
| proc.aggregatePss(data, now); |
| } |
| } |
| } |
| |
| public void reset() { |
| if (DEBUG) Slog.d(TAG, "Resetting state of " + mTimePeriodStartClockStr); |
| resetCommon(); |
| mPackages.getMap().clear(); |
| mProcesses.getMap().clear(); |
| mMemFactor = STATE_NOTHING; |
| mStartTime = 0; |
| if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr); |
| } |
| |
| public void resetSafely() { |
| if (DEBUG) Slog.d(TAG, "Safely resetting state of " + mTimePeriodStartClockStr); |
| resetCommon(); |
| |
| // First initialize use count of all common processes. |
| final long now = SystemClock.uptimeMillis(); |
| final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); |
| for (int ip=procMap.size()-1; ip>=0; ip--) { |
| final SparseArray<ProcessState> uids = procMap.valueAt(ip); |
| for (int iu=uids.size()-1; iu>=0; iu--) { |
| uids.valueAt(iu).tmpNumInUse = 0; |
| } |
| } |
| |
| // Next reset or prune all per-package processes, and for the ones that are reset |
| // track this back to the common processes. |
| final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| mPackages.getMap(); |
| for (int ip=pkgMap.size()-1; ip>=0; ip--) { |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| for (int iu=uids.size()-1; iu>=0; iu--) { |
| final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); |
| for (int iv=vpkgs.size()-1; iv>=0; iv--) { |
| final PackageState pkgState = vpkgs.valueAt(iv); |
| for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) { |
| final ProcessState ps = pkgState.mProcesses.valueAt(iproc); |
| if (ps.isInUse()) { |
| ps.resetSafely(now); |
| ps.getCommonProcess().tmpNumInUse++; |
| ps.getCommonProcess().tmpFoundSubProc = ps; |
| } else { |
| pkgState.mProcesses.valueAt(iproc).makeDead(); |
| pkgState.mProcesses.removeAt(iproc); |
| } |
| } |
| for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) { |
| final ServiceState ss = pkgState.mServices.valueAt(isvc); |
| if (ss.isInUse()) { |
| ss.resetSafely(now); |
| } else { |
| pkgState.mServices.removeAt(isvc); |
| } |
| } |
| for (int iasc=pkgState.mAssociations.size()-1; iasc>=0; iasc--) { |
| final AssociationState as = pkgState.mAssociations.valueAt(iasc); |
| if (as.isInUse()) { |
| as.resetSafely(now); |
| } else { |
| pkgState.mAssociations.removeAt(iasc); |
| } |
| } |
| if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0 |
| && pkgState.mAssociations.size() <= 0) { |
| vpkgs.removeAt(iv); |
| } |
| } |
| if (vpkgs.size() <= 0) { |
| uids.removeAt(iu); |
| } |
| } |
| if (uids.size() <= 0) { |
| pkgMap.removeAt(ip); |
| } |
| } |
| |
| // Finally prune out any common processes that are no longer in use. |
| for (int ip=procMap.size()-1; ip>=0; ip--) { |
| final SparseArray<ProcessState> uids = procMap.valueAt(ip); |
| for (int iu=uids.size()-1; iu>=0; iu--) { |
| ProcessState ps = uids.valueAt(iu); |
| if (ps.isInUse() || ps.tmpNumInUse > 0) { |
| // If this is a process for multiple packages, we could at this point |
| // be back down to one package. In that case, we want to revert back |
| // to a single shared ProcessState. We can do this by converting the |
| // current package-specific ProcessState up to the shared ProcessState, |
| // throwing away the current one we have here (because nobody else is |
| // using it). |
| if (!ps.isActive() && ps.isMultiPackage() && ps.tmpNumInUse == 1) { |
| // Here we go... |
| ps = ps.tmpFoundSubProc; |
| ps.makeStandalone(); |
| uids.setValueAt(iu, ps); |
| } else { |
| ps.resetSafely(now); |
| } |
| } else { |
| ps.makeDead(); |
| uids.removeAt(iu); |
| } |
| } |
| if (uids.size() <= 0) { |
| procMap.removeAt(ip); |
| } |
| } |
| |
| mStartTime = now; |
| if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr); |
| } |
| |
| private void resetCommon() { |
| mTimePeriodStartClock = System.currentTimeMillis(); |
| buildTimePeriodStartClockStr(); |
| mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); |
| mTimePeriodStartUptime = mTimePeriodEndUptime = SystemClock.uptimeMillis(); |
| mInternalSinglePssCount = 0; |
| mInternalSinglePssTime = 0; |
| mInternalAllMemPssCount = 0; |
| mInternalAllMemPssTime = 0; |
| mInternalAllPollPssCount = 0; |
| mInternalAllPollPssTime = 0; |
| mExternalPssCount = 0; |
| mExternalPssTime = 0; |
| mExternalSlowPssCount = 0; |
| mExternalSlowPssTime = 0; |
| mTableData.reset(); |
| Arrays.fill(mMemFactorDurations, 0); |
| mSysMemUsage.resetTable(); |
| mStartTime = 0; |
| mReadError = null; |
| mFlags = 0; |
| evaluateSystemProperties(true); |
| updateFragmentation(); |
| } |
| |
| public boolean evaluateSystemProperties(boolean update) { |
| boolean changed = false; |
| String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2", |
| VMRuntime.getRuntime().vmLibrary()); |
| if (!Objects.equals(runtime, mRuntime)) { |
| changed = true; |
| if (update) { |
| mRuntime = runtime; |
| } |
| } |
| return changed; |
| } |
| |
| private void buildTimePeriodStartClockStr() { |
| mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss", |
| mTimePeriodStartClock).toString(); |
| } |
| |
| static final int[] BAD_TABLE = new int[0]; |
| |
| |
| /** |
| * Load the system's memory fragmentation info. |
| */ |
| public void updateFragmentation() { |
| // Parse /proc/pagetypeinfo and store the values. |
| BufferedReader reader = null; |
| try { |
| reader = new BufferedReader(new FileReader("/proc/pagetypeinfo")); |
| final Matcher matcher = sPageTypeRegex.matcher(""); |
| mPageTypeZones.clear(); |
| mPageTypeLabels.clear(); |
| mPageTypeSizes.clear(); |
| while (true) { |
| final String line = reader.readLine(); |
| if (line == null) { |
| break; |
| } |
| matcher.reset(line); |
| if (matcher.matches()) { |
| final Integer zone = Integer.valueOf(matcher.group(1), 10); |
| if (zone == null) { |
| continue; |
| } |
| mPageTypeZones.add(zone); |
| mPageTypeLabels.add(matcher.group(2)); |
| mPageTypeSizes.add(splitAndParseNumbers(matcher.group(3))); |
| } |
| } |
| } catch (IOException ex) { |
| mPageTypeZones.clear(); |
| mPageTypeLabels.clear(); |
| mPageTypeSizes.clear(); |
| return; |
| } finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } catch (IOException allHopeIsLost) { |
| } |
| } |
| } |
| } |
| |
| /** |
| * Split the string of digits separaed by spaces. There must be no |
| * leading or trailing spaces. The format is ensured by the regex |
| * above. |
| */ |
| private static int[] splitAndParseNumbers(String s) { |
| // These are always positive and the numbers can't be so big that we'll overflow |
| // so just do the parsing inline. |
| boolean digit = false; |
| int count = 0; |
| final int N = s.length(); |
| // Count the numbers |
| for (int i=0; i<N; i++) { |
| final char c = s.charAt(i); |
| if (c >= '0' && c <= '9') { |
| if (!digit) { |
| digit = true; |
| count++; |
| } |
| } else { |
| digit = false; |
| } |
| } |
| // Parse the numbers |
| final int[] result = new int[count]; |
| int p = 0; |
| int val = 0; |
| for (int i=0; i<N; i++) { |
| final char c = s.charAt(i); |
| if (c >= '0' && c <= '9') { |
| if (!digit) { |
| digit = true; |
| val = c - '0'; |
| } else { |
| val *= 10; |
| val += c - '0'; |
| } |
| } else { |
| if (digit) { |
| digit = false; |
| result[p++] = val; |
| } |
| } |
| } |
| if (count > 0) { |
| result[count-1] = val; |
| } |
| return result; |
| } |
| |
| |
| private void writeCompactedLongArray(Parcel out, long[] array, int num) { |
| for (int i=0; i<num; i++) { |
| long val = array[i]; |
| if (val < 0) { |
| Slog.w(TAG, "Time val negative: " + val); |
| val = 0; |
| } |
| if (val <= Integer.MAX_VALUE) { |
| out.writeInt((int)val); |
| } else { |
| int top = ~((int)((val>>32)&0x7fffffff)); |
| int bottom = (int)(val&0x0ffffffffL); |
| out.writeInt(top); |
| out.writeInt(bottom); |
| } |
| } |
| } |
| |
| private void readCompactedLongArray(Parcel in, int version, long[] array, int num) { |
| if (version <= 10) { |
| in.readLongArray(array); |
| return; |
| } |
| final int alen = array.length; |
| if (num > alen) { |
| throw new RuntimeException("bad array lengths: got " + num + " array is " + alen); |
| } |
| int i; |
| for (i=0; i<num; i++) { |
| int val = in.readInt(); |
| if (val >= 0) { |
| array[i] = val; |
| } else { |
| int bottom = in.readInt(); |
| array[i] = (((long)~val)<<32) | bottom; |
| } |
| } |
| while (i < alen) { |
| array[i] = 0; |
| i++; |
| } |
| } |
| |
| void writeCommonString(Parcel out, String name) { |
| Integer index = mCommonStringToIndex.get(name); |
| if (index != null) { |
| out.writeInt(index); |
| return; |
| } |
| index = mCommonStringToIndex.size(); |
| mCommonStringToIndex.put(name, index); |
| out.writeInt(~index); |
| out.writeString(name); |
| } |
| |
| String readCommonString(Parcel in, int version) { |
| if (version <= 9) { |
| return in.readString(); |
| } |
| int index = in.readInt(); |
| if (index >= 0) { |
| return mIndexToCommonString.get(index); |
| } |
| index = ~index; |
| String name = in.readString(); |
| while (mIndexToCommonString.size() <= index) { |
| mIndexToCommonString.add(null); |
| } |
| mIndexToCommonString.set(index, name); |
| return name; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel out, int flags) { |
| writeToParcel(out, SystemClock.uptimeMillis(), flags); |
| } |
| |
| /** @hide */ |
| public void writeToParcel(Parcel out, long now, int flags) { |
| out.writeInt(MAGIC); |
| out.writeInt(PARCEL_VERSION); |
| out.writeInt(STATE_COUNT); |
| out.writeInt(ADJ_COUNT); |
| out.writeInt(PSS_COUNT); |
| out.writeInt(SYS_MEM_USAGE_COUNT); |
| out.writeInt(SparseMappingTable.ARRAY_SIZE); |
| |
| mCommonStringToIndex = new ArrayMap<String, Integer>(mProcesses.size()); |
| |
| // First commit all running times. |
| ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); |
| final int NPROC = procMap.size(); |
| for (int ip=0; ip<NPROC; ip++) { |
| SparseArray<ProcessState> uids = procMap.valueAt(ip); |
| final int NUID = uids.size(); |
| for (int iu=0; iu<NUID; iu++) { |
| uids.valueAt(iu).commitStateTime(now); |
| } |
| } |
| final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| mPackages.getMap(); |
| final int NPKG = pkgMap.size(); |
| for (int ip=0; ip<NPKG; ip++) { |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| final int NUID = uids.size(); |
| for (int iu=0; iu<NUID; iu++) { |
| final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); |
| final int NVERS = vpkgs.size(); |
| for (int iv=0; iv<NVERS; iv++) { |
| PackageState pkgState = vpkgs.valueAt(iv); |
| final int NPROCS = pkgState.mProcesses.size(); |
| for (int iproc=0; iproc<NPROCS; iproc++) { |
| ProcessState proc = pkgState.mProcesses.valueAt(iproc); |
| if (proc.getCommonProcess() != proc) { |
| proc.commitStateTime(now); |
| } |
| } |
| final int NSRVS = pkgState.mServices.size(); |
| for (int isvc=0; isvc<NSRVS; isvc++) { |
| pkgState.mServices.valueAt(isvc).commitStateTime(now); |
| } |
| final int NASCS = pkgState.mAssociations.size(); |
| for (int iasc=0; iasc<NASCS; iasc++) { |
| pkgState.mAssociations.valueAt(iasc).commitStateTime(now); |
| } |
| } |
| } |
| } |
| |
| out.writeLong(mTimePeriodStartClock); |
| out.writeLong(mTimePeriodStartRealtime); |
| out.writeLong(mTimePeriodEndRealtime); |
| out.writeLong(mTimePeriodStartUptime); |
| out.writeLong(mTimePeriodEndUptime); |
| out.writeLong(mInternalSinglePssCount); |
| out.writeLong(mInternalSinglePssTime); |
| out.writeLong(mInternalAllMemPssCount); |
| out.writeLong(mInternalAllMemPssTime); |
| out.writeLong(mInternalAllPollPssCount); |
| out.writeLong(mInternalAllPollPssTime); |
| out.writeLong(mExternalPssCount); |
| out.writeLong(mExternalPssTime); |
| out.writeLong(mExternalSlowPssCount); |
| out.writeLong(mExternalSlowPssTime); |
| out.writeString(mRuntime); |
| out.writeInt(mHasSwappedOutPss ? 1 : 0); |
| out.writeInt(mFlags); |
| |
| mTableData.writeToParcel(out); |
| |
| if (mMemFactor != STATE_NOTHING) { |
| mMemFactorDurations[mMemFactor] += now - mStartTime; |
| mStartTime = now; |
| } |
| writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length); |
| |
| mSysMemUsage.writeToParcel(out); |
| |
| out.writeInt(NPROC); |
| for (int ip=0; ip<NPROC; ip++) { |
| writeCommonString(out, procMap.keyAt(ip)); |
| final SparseArray<ProcessState> uids = procMap.valueAt(ip); |
| final int NUID = uids.size(); |
| out.writeInt(NUID); |
| for (int iu=0; iu<NUID; iu++) { |
| out.writeInt(uids.keyAt(iu)); |
| final ProcessState proc = uids.valueAt(iu); |
| writeCommonString(out, proc.getPackage()); |
| out.writeLong(proc.getVersion()); |
| proc.writeToParcel(out, now); |
| } |
| } |
| out.writeInt(NPKG); |
| for (int ip=0; ip<NPKG; ip++) { |
| writeCommonString(out, pkgMap.keyAt(ip)); |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| final int NUID = uids.size(); |
| out.writeInt(NUID); |
| for (int iu=0; iu<NUID; iu++) { |
| out.writeInt(uids.keyAt(iu)); |
| final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); |
| final int NVERS = vpkgs.size(); |
| out.writeInt(NVERS); |
| for (int iv=0; iv<NVERS; iv++) { |
| out.writeLong(vpkgs.keyAt(iv)); |
| final PackageState pkgState = vpkgs.valueAt(iv); |
| final int NPROCS = pkgState.mProcesses.size(); |
| out.writeInt(NPROCS); |
| for (int iproc=0; iproc<NPROCS; iproc++) { |
| writeCommonString(out, pkgState.mProcesses.keyAt(iproc)); |
| final ProcessState proc = pkgState.mProcesses.valueAt(iproc); |
| if (proc.getCommonProcess() == proc) { |
| // This is the same as the common process we wrote above. |
| out.writeInt(0); |
| } else { |
| // There is separate data for this package's process. |
| out.writeInt(1); |
| proc.writeToParcel(out, now); |
| } |
| } |
| final int NSRVS = pkgState.mServices.size(); |
| out.writeInt(NSRVS); |
| for (int isvc=0; isvc<NSRVS; isvc++) { |
| out.writeString(pkgState.mServices.keyAt(isvc)); |
| final ServiceState svc = pkgState.mServices.valueAt(isvc); |
| writeCommonString(out, svc.getProcessName()); |
| svc.writeToParcel(out, now); |
| } |
| final int NASCS = pkgState.mAssociations.size(); |
| out.writeInt(NASCS); |
| for (int iasc=0; iasc<NASCS; iasc++) { |
| writeCommonString(out, pkgState.mAssociations.keyAt(iasc)); |
| final AssociationState asc = pkgState.mAssociations.valueAt(iasc); |
| writeCommonString(out, asc.getProcessName()); |
| asc.writeToParcel(this, out, now); |
| } |
| } |
| } |
| } |
| |
| // Fragmentation info (/proc/pagetypeinfo) |
| final int NPAGETYPES = mPageTypeLabels.size(); |
| out.writeInt(NPAGETYPES); |
| for (int i=0; i<NPAGETYPES; i++) { |
| out.writeInt(mPageTypeZones.get(i)); |
| out.writeString(mPageTypeLabels.get(i)); |
| out.writeIntArray(mPageTypeSizes.get(i)); |
| } |
| |
| mCommonStringToIndex = null; |
| } |
| |
| private boolean readCheckedInt(Parcel in, int val, String what) { |
| int got; |
| if ((got=in.readInt()) != val) { |
| mReadError = "bad " + what + ": " + got; |
| return false; |
| } |
| return true; |
| } |
| |
| static byte[] readFully(InputStream stream, int[] outLen) throws IOException { |
| int pos = 0; |
| final int initialAvail = stream.available(); |
| byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384]; |
| while (true) { |
| int amt = stream.read(data, pos, data.length-pos); |
| if (DEBUG_PARCEL) Slog.i("foo", "Read " + amt + " bytes at " + pos |
| + " of avail " + data.length); |
| if (amt < 0) { |
| if (DEBUG_PARCEL) Slog.i("foo", "**** FINISHED READING: pos=" + pos |
| + " len=" + data.length); |
| outLen[0] = pos; |
| return data; |
| } |
| pos += amt; |
| if (pos >= data.length) { |
| byte[] newData = new byte[pos+16384]; |
| if (DEBUG_PARCEL) Slog.i(TAG, "Copying " + pos + " bytes to new array len " |
| + newData.length); |
| System.arraycopy(data, 0, newData, 0, pos); |
| data = newData; |
| } |
| } |
| } |
| |
| public void read(InputStream stream) { |
| try { |
| int[] len = new int[1]; |
| byte[] raw = readFully(stream, len); |
| Parcel in = Parcel.obtain(); |
| in.unmarshall(raw, 0, len[0]); |
| in.setDataPosition(0); |
| stream.close(); |
| |
| readFromParcel(in); |
| } catch (IOException e) { |
| mReadError = "caught exception: " + e; |
| } |
| } |
| |
| public void readFromParcel(Parcel in) { |
| final boolean hadData = mPackages.getMap().size() > 0 |
| || mProcesses.getMap().size() > 0; |
| if (hadData) { |
| resetSafely(); |
| } |
| |
| if (!readCheckedInt(in, MAGIC, "magic number")) { |
| return; |
| } |
| int version = in.readInt(); |
| if (version != PARCEL_VERSION) { |
| mReadError = "bad version: " + version; |
| return; |
| } |
| if (!readCheckedInt(in, STATE_COUNT, "state count")) { |
| return; |
| } |
| if (!readCheckedInt(in, ADJ_COUNT, "adj count")) { |
| return; |
| } |
| if (!readCheckedInt(in, PSS_COUNT, "pss count")) { |
| return; |
| } |
| if (!readCheckedInt(in, SYS_MEM_USAGE_COUNT, "sys mem usage count")) { |
| return; |
| } |
| if (!readCheckedInt(in, SparseMappingTable.ARRAY_SIZE, "longs size")) { |
| return; |
| } |
| |
| mIndexToCommonString = new ArrayList<String>(); |
| |
| mTimePeriodStartClock = in.readLong(); |
| buildTimePeriodStartClockStr(); |
| mTimePeriodStartRealtime = in.readLong(); |
| mTimePeriodEndRealtime = in.readLong(); |
| mTimePeriodStartUptime = in.readLong(); |
| mTimePeriodEndUptime = in.readLong(); |
| mInternalSinglePssCount = in.readLong(); |
| mInternalSinglePssTime = in.readLong(); |
| mInternalAllMemPssCount = in.readLong(); |
| mInternalAllMemPssTime = in.readLong(); |
| mInternalAllPollPssCount = in.readLong(); |
| mInternalAllPollPssTime = in.readLong(); |
| mExternalPssCount = in.readLong(); |
| mExternalPssTime = in.readLong(); |
| mExternalSlowPssCount = in.readLong(); |
| mExternalSlowPssTime = in.readLong(); |
| mRuntime = in.readString(); |
| mHasSwappedOutPss = in.readInt() != 0; |
| mFlags = in.readInt(); |
| mTableData.readFromParcel(in); |
| readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length); |
| if (!mSysMemUsage.readFromParcel(in)) { |
| return; |
| } |
| |
| int NPROC = in.readInt(); |
| if (NPROC < 0) { |
| mReadError = "bad process count: " + NPROC; |
| return; |
| } |
| while (NPROC > 0) { |
| NPROC--; |
| final String procName = readCommonString(in, version); |
| if (procName == null) { |
| mReadError = "bad process name"; |
| return; |
| } |
| int NUID = in.readInt(); |
| if (NUID < 0) { |
| mReadError = "bad uid count: " + NUID; |
| return; |
| } |
| while (NUID > 0) { |
| NUID--; |
| final int uid = in.readInt(); |
| if (uid < 0) { |
| mReadError = "bad uid: " + uid; |
| return; |
| } |
| final String pkgName = readCommonString(in, version); |
| if (pkgName == null) { |
| mReadError = "bad process package name"; |
| return; |
| } |
| final long vers = in.readLong(); |
| ProcessState proc = hadData ? mProcesses.get(procName, uid) : null; |
| if (proc != null) { |
| if (!proc.readFromParcel(in, false)) { |
| return; |
| } |
| } else { |
| proc = new ProcessState(this, pkgName, uid, vers, procName); |
| if (!proc.readFromParcel(in, true)) { |
| return; |
| } |
| } |
| if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid |
| + " " + proc); |
| mProcesses.put(procName, uid, proc); |
| } |
| } |
| |
| if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes"); |
| |
| int NPKG = in.readInt(); |
| if (NPKG < 0) { |
| mReadError = "bad package count: " + NPKG; |
| return; |
| } |
| while (NPKG > 0) { |
| NPKG--; |
| final String pkgName = readCommonString(in, version); |
| if (pkgName == null) { |
| mReadError = "bad package name"; |
| return; |
| } |
| int NUID = in.readInt(); |
| if (NUID < 0) { |
| mReadError = "bad uid count: " + NUID; |
| return; |
| } |
| while (NUID > 0) { |
| NUID--; |
| final int uid = in.readInt(); |
| if (uid < 0) { |
| mReadError = "bad uid: " + uid; |
| return; |
| } |
| int NVERS = in.readInt(); |
| if (NVERS < 0) { |
| mReadError = "bad versions count: " + NVERS; |
| return; |
| } |
| while (NVERS > 0) { |
| NVERS--; |
| final long vers = in.readLong(); |
| PackageState pkgState = new PackageState(this, pkgName, uid, vers); |
| LongSparseArray<PackageState> vpkg = mPackages.get(pkgName, uid); |
| if (vpkg == null) { |
| vpkg = new LongSparseArray<>(); |
| mPackages.put(pkgName, uid, vpkg); |
| } |
| vpkg.put(vers, pkgState); |
| int NPROCS = in.readInt(); |
| if (NPROCS < 0) { |
| mReadError = "bad package process count: " + NPROCS; |
| return; |
| } |
| while (NPROCS > 0) { |
| NPROCS--; |
| String procName = readCommonString(in, version); |
| if (procName == null) { |
| mReadError = "bad package process name"; |
| return; |
| } |
| int hasProc = in.readInt(); |
| if (DEBUG_PARCEL) Slog.d(TAG, "Reading package " + pkgName + " " + uid |
| + " process " + procName + " hasProc=" + hasProc); |
| ProcessState commonProc = mProcesses.get(procName, uid); |
| if (DEBUG_PARCEL) Slog.d(TAG, "Got common proc " + procName + " " + uid |
| + ": " + commonProc); |
| if (commonProc == null) { |
| mReadError = "no common proc: " + procName; |
| return; |
| } |
| if (hasProc != 0) { |
| // The process for this package is unique to the package; we |
| // need to load it. We don't need to do anything about it if |
| // it is not unique because if someone later looks for it |
| // they will find and use it from the global procs. |
| ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null; |
| if (proc != null) { |
| if (!proc.readFromParcel(in, false)) { |
| return; |
| } |
| } else { |
| proc = new ProcessState(commonProc, pkgName, uid, vers, procName, |
| 0); |
| if (!proc.readFromParcel(in, true)) { |
| return; |
| } |
| } |
| if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: " |
| + procName + " " + uid + " " + proc); |
| pkgState.mProcesses.put(procName, proc); |
| } else { |
| if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " process: " |
| + procName + " " + uid + " " + commonProc); |
| pkgState.mProcesses.put(procName, commonProc); |
| } |
| } |
| int NSRVS = in.readInt(); |
| if (NSRVS < 0) { |
| mReadError = "bad package service count: " + NSRVS; |
| return; |
| } |
| while (NSRVS > 0) { |
| NSRVS--; |
| String serviceName = in.readString(); |
| if (serviceName == null) { |
| mReadError = "bad package service name"; |
| return; |
| } |
| String processName = version > 9 ? readCommonString(in, version) : null; |
| ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null; |
| if (serv == null) { |
| serv = new ServiceState(this, pkgName, serviceName, processName, null); |
| } |
| if (!serv.readFromParcel(in)) { |
| return; |
| } |
| if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " service: " |
| + serviceName + " " + uid + " " + serv); |
| pkgState.mServices.put(serviceName, serv); |
| } |
| int NASCS = in.readInt(); |
| if (NASCS < 0) { |
| mReadError = "bad package association count: " + NASCS; |
| return; |
| } |
| while (NASCS > 0) { |
| NASCS--; |
| String associationName = readCommonString(in, version); |
| if (associationName == null) { |
| mReadError = "bad package association name"; |
| return; |
| } |
| String processName = readCommonString(in, version); |
| AssociationState asc = hadData |
| ? pkgState.mAssociations.get(associationName) : null; |
| if (asc == null) { |
| asc = new AssociationState(this, pkgState, associationName, |
| processName, null); |
| } |
| String errorMsg = asc.readFromParcel(this, in, version); |
| if (errorMsg != null) { |
| mReadError = errorMsg; |
| return; |
| } |
| if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " association: " |
| + associationName + " " + uid + " " + asc); |
| pkgState.mAssociations.put(associationName, asc); |
| } |
| } |
| } |
| } |
| |
| // Fragmentation info |
| final int NPAGETYPES = in.readInt(); |
| mPageTypeZones.clear(); |
| mPageTypeZones.ensureCapacity(NPAGETYPES); |
| mPageTypeLabels.clear(); |
| mPageTypeLabels.ensureCapacity(NPAGETYPES); |
| mPageTypeSizes.clear(); |
| mPageTypeSizes.ensureCapacity(NPAGETYPES); |
| for (int i=0; i<NPAGETYPES; i++) { |
| mPageTypeZones.add(in.readInt()); |
| mPageTypeLabels.add(in.readString()); |
| mPageTypeSizes.add(in.createIntArray()); |
| } |
| |
| mIndexToCommonString = null; |
| |
| if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!"); |
| } |
| |
| public PackageState getPackageStateLocked(String packageName, int uid, long vers) { |
| LongSparseArray<PackageState> vpkg = mPackages.get(packageName, uid); |
| if (vpkg == null) { |
| vpkg = new LongSparseArray<>(); |
| mPackages.put(packageName, uid, vpkg); |
| } |
| PackageState as = vpkg.get(vers); |
| if (as != null) { |
| return as; |
| } |
| as = new PackageState(this, packageName, uid, vers); |
| vpkg.put(vers, as); |
| return as; |
| } |
| |
| public ProcessState getProcessStateLocked(String packageName, int uid, long vers, |
| String processName) { |
| return getProcessStateLocked(getPackageStateLocked(packageName, uid, vers), processName); |
| } |
| |
| public ProcessState getProcessStateLocked(PackageState pkgState, String processName) { |
| ProcessState ps = pkgState.mProcesses.get(processName); |
| if (ps != null) { |
| return ps; |
| } |
| ProcessState commonProc = mProcesses.get(processName, pkgState.mUid); |
| if (commonProc == null) { |
| commonProc = new ProcessState(this, pkgState.mPackageName, pkgState.mUid, |
| pkgState.mVersionCode, processName); |
| mProcesses.put(processName, pkgState.mUid, commonProc); |
| if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc); |
| } |
| if (!commonProc.isMultiPackage()) { |
| if (pkgState.mPackageName.equals(commonProc.getPackage()) |
| && pkgState.mVersionCode == commonProc.getVersion()) { |
| // This common process is not in use by multiple packages, and |
| // is for the calling package, so we can just use it directly. |
| ps = commonProc; |
| if (DEBUG) Slog.d(TAG, "GETPROC also using for pkg " + commonProc); |
| } else { |
| if (DEBUG) Slog.d(TAG, "GETPROC need to split common proc!"); |
| // This common process has not been in use by multiple packages, |
| // but it was created for a different package than the caller. |
| // We need to convert it to a multi-package process. |
| commonProc.setMultiPackage(true); |
| // To do this, we need to make two new process states, one a copy |
| // of the current state for the process under the original package |
| // name, and the second a free new process state for it as the |
| // new package name. |
| long now = SystemClock.uptimeMillis(); |
| // First let's make a copy of the current process state and put |
| // that under the now unique state for its original package name. |
| final PackageState commonPkgState = getPackageStateLocked(commonProc.getPackage(), |
| pkgState.mUid, commonProc.getVersion()); |
| if (commonPkgState != null) { |
| ProcessState cloned = commonProc.clone(now); |
| if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.getPackage() |
| + ": " + cloned); |
| commonPkgState.mProcesses.put(commonProc.getName(), cloned); |
| // If this has active services, we need to update their process pointer |
| // to point to the new package-specific process state. |
| for (int i=commonPkgState.mServices.size()-1; i>=0; i--) { |
| ServiceState ss = commonPkgState.mServices.valueAt(i); |
| if (ss.getProcess() == commonProc) { |
| if (DEBUG) Slog.d(TAG, "GETPROC switching service to cloned: " + ss); |
| ss.setProcess(cloned); |
| } else if (DEBUG) { |
| Slog.d(TAG, "GETPROC leaving proc of " + ss); |
| } |
| } |
| // Also update active associations. |
| for (int i=commonPkgState.mAssociations.size()-1; i>=0; i--) { |
| AssociationState as = commonPkgState.mAssociations.valueAt(i); |
| if (as.getProcess() == commonProc) { |
| if (DEBUG) Slog.d(TAG, "GETPROC switching association to cloned: " |
| + as); |
| as.setProcess(cloned); |
| } else if (DEBUG) { |
| Slog.d(TAG, "GETPROC leaving proc of " + as); |
| } |
| } |
| } else { |
| Slog.w(TAG, "Cloning proc state: no package state " + commonProc.getPackage() |
| + "/" + pkgState.mUid + " for proc " + commonProc.getName()); |
| } |
| // And now make a fresh new process state for the new package name. |
| ps = new ProcessState(commonProc, pkgState.mPackageName, pkgState.mUid, |
| pkgState.mVersionCode, processName, now); |
| if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps); |
| } |
| } else { |
| // The common process is for multiple packages, we need to create a |
| // separate object for the per-package data. |
| ps = new ProcessState(commonProc, pkgState.mPackageName, pkgState.mUid, |
| pkgState.mVersionCode, processName, |
| SystemClock.uptimeMillis()); |
| if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps); |
| } |
| pkgState.mProcesses.put(processName, ps); |
| if (DEBUG) Slog.d(TAG, "GETPROC adding new pkg " + ps); |
| return ps; |
| } |
| |
| public ServiceState getServiceStateLocked(String packageName, int uid, long vers, |
| String processName, String className) { |
| final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers); |
| ServiceState ss = as.mServices.get(className); |
| if (ss != null) { |
| if (DEBUG) Slog.d(TAG, "GETSVC: returning existing " + ss); |
| return ss; |
| } |
| final ProcessState ps = processName != null |
| ? getProcessStateLocked(packageName, uid, vers, processName) : null; |
| ss = new ServiceState(this, packageName, className, processName, ps); |
| as.mServices.put(className, ss); |
| if (DEBUG) Slog.d(TAG, "GETSVC: creating " + ss + " in " + ps); |
| return ss; |
| } |
| |
| public AssociationState getAssociationStateLocked(String packageName, int uid, long vers, |
| String processName, String className) { |
| final ProcessStats.PackageState pkgs = getPackageStateLocked(packageName, uid, vers); |
| AssociationState as = pkgs.mAssociations.get(className); |
| if (as != null) { |
| if (DEBUG) Slog.d(TAG, "GETASC: returning existing " + as); |
| return as; |
| } |
| final ProcessState procs = processName != null |
| ? getProcessStateLocked(packageName, uid, vers, processName) : null; |
| as = new AssociationState(this, pkgs, className, processName, procs); |
| pkgs.mAssociations.put(className, as); |
| if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + procs); |
| return as; |
| } |
| |
| // See b/118826162 -- to avoid logspaming, we rate limit the warnings. |
| private static final long INVERSE_PROC_STATE_WARNING_MIN_INTERVAL_MS = 10_000L; |
| private long mNextInverseProcStateWarningUptime; |
| private int mSkippedInverseProcStateWarningCount; |
| |
| public void updateTrackingAssociationsLocked(int curSeq, long now) { |
| final int NUM = mTrackingAssociations.size(); |
| for (int i = NUM - 1; i >= 0; i--) { |
| final AssociationState.SourceState act = mTrackingAssociations.get(i); |
| if (act.mProcStateSeq != curSeq || act.mProcState >= ProcessStats.STATE_HOME) { |
| // 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); |
| } else { |
| final ProcessState proc = act.getAssociationState().getProcess(); |
| if (proc != null) { |
| final int procState = proc.getCombinedState() % STATE_COUNT; |
| if (act.mProcState == procState) { |
| act.startActive(now); |
| } else { |
| act.stopActive(now); |
| if (act.mProcState < procState) { |
| final long nowUptime = SystemClock.uptimeMillis(); |
| if (mNextInverseProcStateWarningUptime > nowUptime) { |
| mSkippedInverseProcStateWarningCount++; |
| } else { |
| // TODO We still see it during boot related to GMS-core. |
| // b/118826162 |
| Slog.w(TAG, "Tracking association " + act + " whose proc state " |
| + act.mProcState + " is better than process " + proc |
| + " proc state " + procState |
| + " (" + mSkippedInverseProcStateWarningCount |
| + " skipped)"); |
| mSkippedInverseProcStateWarningCount = 0; |
| mNextInverseProcStateWarningUptime = |
| nowUptime + INVERSE_PROC_STATE_WARNING_MIN_INTERVAL_MS; |
| } |
| } |
| } |
| } else { |
| // Don't need rate limiting on it. |
| Slog.wtf(TAG, "Tracking association without process: " + act |
| + " in " + act.getAssociationState()); |
| } |
| } |
| } |
| } |
| |
| public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary, |
| boolean dumpDetails, boolean dumpAll, boolean activeOnly, int section) { |
| long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, |
| mStartTime, now); |
| boolean sepNeeded = false; |
| if (mSysMemUsage.getKeyCount() > 0) { |
| pw.println("System memory usage:"); |
| mSysMemUsage.dump(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ); |
| sepNeeded = true; |
| } |
| boolean printedHeader = false; |
| if ((section & REPORT_PKG_STATS) != 0) { |
| ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| mPackages.getMap(); |
| for (int ip = 0; ip < pkgMap.size(); ip++) { |
| final String pkgName = pkgMap.keyAt(ip); |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| for (int iu = 0; iu < uids.size(); iu++) { |
| final int uid = uids.keyAt(iu); |
| final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); |
| for (int iv = 0; iv < vpkgs.size(); iv++) { |
| final long vers = vpkgs.keyAt(iv); |
| final PackageState pkgState = vpkgs.valueAt(iv); |
| final int NPROCS = pkgState.mProcesses.size(); |
| final int NSRVS = pkgState.mServices.size(); |
| final int NASCS = pkgState.mAssociations.size(); |
| final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); |
| boolean onlyAssociations = false; |
| if (!pkgMatch) { |
| boolean procMatch = false; |
| for (int iproc = 0; iproc < NPROCS; iproc++) { |
| ProcessState proc = pkgState.mProcesses.valueAt(iproc); |
| if (reqPackage.equals(proc.getName())) { |
| procMatch = true; |
| break; |
| } |
| } |
| if (!procMatch) { |
| // Check if this app has any associations with the requested |
| // package, so that if so we print those. |
| for (int iasc = 0; iasc < NASCS; iasc++) { |
| AssociationState asc = pkgState.mAssociations.valueAt(iasc); |
| if (asc.hasProcessOrPackage(reqPackage)) { |
| onlyAssociations = true; |
| break; |
| } |
| } |
| if (!onlyAssociations) { |
| continue; |
| } |
| } |
| } |
| if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) { |
| if (!printedHeader) { |
| if (sepNeeded) pw.println(); |
| pw.println("Per-Package Stats:"); |
| printedHeader = true; |
| sepNeeded = true; |
| } |
| pw.print(" * "); |
| pw.print(pkgName); |
| pw.print(" / "); |
| UserHandle.formatUid(pw, uid); |
| pw.print(" / v"); |
| pw.print(vers); |
| pw.println(":"); |
| } |
| if ((section & REPORT_PKG_PROC_STATS) != 0 && !onlyAssociations) { |
| if (!dumpSummary || dumpAll) { |
| for (int iproc = 0; iproc < NPROCS; iproc++) { |
| ProcessState proc = pkgState.mProcesses.valueAt(iproc); |
| if (!pkgMatch && !reqPackage.equals(proc.getName())) { |
| continue; |
| } |
| if (activeOnly && !proc.isInUse()) { |
| pw.print(" (Not active: "); |
| pw.print(pkgState.mProcesses.keyAt(iproc)); |
| pw.println(")"); |
| continue; |
| } |
| pw.print(" Process "); |
| pw.print(pkgState.mProcesses.keyAt(iproc)); |
| if (proc.getCommonProcess().isMultiPackage()) { |
| pw.print(" (multi, "); |
| } else { |
| pw.print(" (unique, "); |
| } |
| pw.print(proc.getDurationsBucketCount()); |
| pw.print(" entries)"); |
| pw.println(":"); |
| proc.dumpProcessState(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); |
| } |
| } else { |
| ArrayList<ProcessState> procs = new ArrayList<ProcessState>(); |
| for (int iproc = 0; iproc < NPROCS; iproc++) { |
| ProcessState proc = pkgState.mProcesses.valueAt(iproc); |
| if (!pkgMatch && !reqPackage.equals(proc.getName())) { |
| continue; |
| } |
| if (activeOnly && !proc.isInUse()) { |
| continue; |
| } |
| procs.add(proc); |
| } |
| DumpUtils.dumpProcessSummaryLocked(pw, " ", "Prc ", procs, |
| ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES, |
| now, totalTime); |
| } |
| } |
| if ((section & REPORT_PKG_SVC_STATS) != 0 && !onlyAssociations) { |
| for (int isvc = 0; isvc < NSRVS; isvc++) { |
| ServiceState svc = pkgState.mServices.valueAt(isvc); |
| if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) { |
| continue; |
| } |
| if (activeOnly && !svc.isInUse()) { |
| pw.print(" (Not active service: "); |
| pw.print(pkgState.mServices.keyAt(isvc)); |
| pw.println(")"); |
| continue; |
| } |
| if (dumpAll) { |
| pw.print(" Service "); |
| } else { |
| pw.print(" * Svc "); |
| } |
| pw.print(pkgState.mServices.keyAt(isvc)); |
| pw.println(":"); |
| pw.print(" Process: "); |
| pw.println(svc.getProcessName()); |
| svc.dumpStats(pw, " ", " ", " ", |
| now, totalTime, dumpSummary, dumpAll); |
| } |
| } |
| if ((section & REPORT_PKG_ASC_STATS) != 0) { |
| for (int iasc = 0; iasc < NASCS; iasc++) { |
| AssociationState asc = pkgState.mAssociations.valueAt(iasc); |
| if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) { |
| if (!onlyAssociations || !asc.hasProcessOrPackage(reqPackage)) { |
| continue; |
| } |
| } |
| if (activeOnly && !asc.isInUse()) { |
| pw.print(" (Not active association: "); |
| pw.print(pkgState.mAssociations.keyAt(iasc)); |
| pw.println(")"); |
| continue; |
| } |
| if (dumpAll) { |
| pw.print(" Association "); |
| } else { |
| pw.print(" * Asc "); |
| } |
| pw.print(pkgState.mAssociations.keyAt(iasc)); |
| pw.println(":"); |
| pw.print(" Process: "); |
| pw.println(asc.getProcessName()); |
| asc.dumpStats(pw, " ", " ", " ", |
| now, totalTime, onlyAssociations ? reqPackage : null, |
| dumpDetails, dumpAll); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if ((section & REPORT_PROC_STATS) != 0) { |
| ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); |
| printedHeader = false; |
| int numShownProcs = 0, numTotalProcs = 0; |
| 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++) { |
| int uid = uids.keyAt(iu); |
| numTotalProcs++; |
| final ProcessState proc = uids.valueAt(iu); |
| if (!proc.hasAnyData()) { |
| continue; |
| } |
| if (!proc.isMultiPackage()) { |
| continue; |
| } |
| if (reqPackage != null && !reqPackage.equals(procName) |
| && !reqPackage.equals(proc.getPackage())) { |
| continue; |
| } |
| numShownProcs++; |
| if (sepNeeded) { |
| pw.println(); |
| } |
| sepNeeded = true; |
| if (!printedHeader) { |
| pw.println("Multi-Package Common Processes:"); |
| printedHeader = true; |
| } |
| if (activeOnly && !proc.isInUse()) { |
| pw.print(" (Not active: "); |
| pw.print(procName); |
| pw.println(")"); |
| continue; |
| } |
| pw.print(" * "); |
| pw.print(procName); |
| pw.print(" / "); |
| UserHandle.formatUid(pw, uid); |
| pw.print(" ("); |
| pw.print(proc.getDurationsBucketCount()); |
| pw.print(" entries)"); |
| pw.println(":"); |
| proc.dumpProcessState(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); |
| } |
| } |
| pw.print(" Total procs: "); pw.print(numShownProcs); |
| pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total"); |
| } |
| |
| if (dumpAll) { |
| if (sepNeeded) { |
| pw.println(); |
| } |
| sepNeeded = true; |
| |
| if (mTrackingAssociations.size() > 0) { |
| pw.println(); |
| pw.println("Tracking associations:"); |
| for (int i = 0; i < mTrackingAssociations.size(); i++) { |
| final AssociationState.SourceState src = mTrackingAssociations.get(i); |
| final AssociationState asc = src.getAssociationState(); |
| pw.print(" #"); |
| pw.print(i); |
| pw.print(": "); |
| pw.print(asc.getProcessName()); |
| pw.print("/"); |
| UserHandle.formatUid(pw, asc.getUid()); |
| pw.print(" <- "); |
| pw.print(src.getProcessName()); |
| pw.print("/"); |
| UserHandle.formatUid(pw, src.getUid()); |
| pw.println(":"); |
| pw.print(" Tracking for: "); |
| TimeUtils.formatDuration(now - src.mTrackingUptime, pw); |
| pw.println(); |
| pw.print(" Component: "); |
| pw.print(new ComponentName(asc.getPackage(), asc.getName()) |
| .flattenToShortString()); |
| pw.println(); |
| pw.print(" Proc state: "); |
| if (src.mProcState != ProcessStats.STATE_NOTHING) { |
| pw.print(DumpUtils.STATE_NAMES[src.mProcState]); |
| } else { |
| pw.print("--"); |
| } |
| pw.print(" #"); |
| pw.println(src.mProcStateSeq); |
| pw.print(" Process: "); |
| pw.println(asc.getProcess()); |
| if (src.mActiveCount > 0) { |
| pw.print(" Active count "); |
| pw.print(src.mActiveCount); |
| pw.print(": "); |
| asc.dumpActiveDurationSummary(pw, src, totalTime, now, dumpAll); |
| pw.println(); |
| } |
| } |
| } |
| } |
| |
| if (sepNeeded) { |
| pw.println(); |
| } |
| if (dumpSummary) { |
| pw.println("Process summary:"); |
| dumpSummaryLocked(pw, reqPackage, now, activeOnly); |
| } else { |
| dumpTotalsLocked(pw, now); |
| } |
| |
| if (dumpAll) { |
| pw.println(); |
| pw.println("Internal state:"); |
| /* |
| pw.print(" Num long arrays: "); pw.println(mLongs.size()); |
| pw.print(" Next long entry: "); pw.println(mNextLong); |
| */ |
| pw.print(" mRunning="); pw.println(mRunning); |
| } |
| |
| if (reqPackage == null) { |
| dumpFragmentationLocked(pw); |
| } |
| } |
| |
| public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) { |
| long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, |
| mStartTime, now); |
| dumpFilteredSummaryLocked(pw, null, " ", null, ALL_SCREEN_ADJ, ALL_MEM_ADJ, |
| ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly); |
| pw.println(); |
| dumpTotalsLocked(pw, now); |
| } |
| |
| private void dumpFragmentationLocked(PrintWriter pw) { |
| pw.println(); |
| pw.println("Available pages by page size:"); |
| final int NPAGETYPES = mPageTypeLabels.size(); |
| for (int i=0; i<NPAGETYPES; i++) { |
| pw.format("Zone %3d %14s ", mPageTypeZones.get(i), mPageTypeLabels.get(i)); |
| final int[] sizes = mPageTypeSizes.get(i); |
| final int N = sizes == null ? 0 : sizes.length; |
| for (int j=0; j<N; j++) { |
| pw.format("%6d", sizes[j]); |
| } |
| pw.println(); |
| } |
| } |
| |
| long printMemoryCategory(PrintWriter pw, String prefix, String label, double memWeight, |
| long totalTime, long curTotalMem, int samples) { |
| if (memWeight != 0) { |
| long mem = (long)(memWeight * 1024 / totalTime); |
| pw.print(prefix); |
| pw.print(label); |
| pw.print(": "); |
| DebugUtils.printSizeValue(pw, mem); |
| pw.print(" ("); |
| pw.print(samples); |
| pw.print(" samples)"); |
| pw.println(); |
| return curTotalMem + mem; |
| } |
| return curTotalMem; |
| } |
| |
| void dumpTotalsLocked(PrintWriter pw, long now) { |
| pw.println("Run time Stats:"); |
| DumpUtils.dumpSingleTime(pw, " ", mMemFactorDurations, mMemFactor, mStartTime, now); |
| pw.println(); |
| pw.println("Memory usage:"); |
| TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ, |
| ALL_MEM_ADJ); |
| computeTotalMemoryUse(totalMem, now); |
| long totalPss = 0; |
| totalPss = printMemoryCategory(pw, " ", "Kernel ", totalMem.sysMemKernelWeight, |
| totalMem.totalTime, totalPss, totalMem.sysMemSamples); |
| totalPss = printMemoryCategory(pw, " ", "Native ", totalMem.sysMemNativeWeight, |
| totalMem.totalTime, totalPss, totalMem.sysMemSamples); |
| for (int i=0; i<STATE_COUNT; i++) { |
| // Skip restarting service state -- that is not actually a running process. |
| if (i != STATE_SERVICE_RESTARTING) { |
| totalPss = printMemoryCategory(pw, " ", DumpUtils.STATE_NAMES[i], |
| totalMem.processStateWeight[i], totalMem.totalTime, totalPss, |
| totalMem.processStateSamples[i]); |
| } |
| } |
| totalPss = printMemoryCategory(pw, " ", "Cached ", totalMem.sysMemCachedWeight, |
| totalMem.totalTime, totalPss, totalMem.sysMemSamples); |
| totalPss = printMemoryCategory(pw, " ", "Free ", totalMem.sysMemFreeWeight, |
| totalMem.totalTime, totalPss, totalMem.sysMemSamples); |
| totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight, |
| totalMem.totalTime, totalPss, totalMem.sysMemSamples); |
| pw.print(" TOTAL : "); |
| DebugUtils.printSizeValue(pw, totalPss); |
| pw.println(); |
| printMemoryCategory(pw, " ", DumpUtils.STATE_NAMES[STATE_SERVICE_RESTARTING], |
| totalMem.processStateWeight[STATE_SERVICE_RESTARTING], totalMem.totalTime, totalPss, |
| totalMem.processStateSamples[STATE_SERVICE_RESTARTING]); |
| pw.println(); |
| pw.println("PSS collection stats:"); |
| pw.print(" Internal Single: "); |
| pw.print(mInternalSinglePssCount); |
| pw.print("x over "); |
| TimeUtils.formatDuration(mInternalSinglePssTime, pw); |
| pw.println(); |
| pw.print(" Internal All Procs (Memory Change): "); |
| pw.print(mInternalAllMemPssCount); |
| pw.print("x over "); |
| TimeUtils.formatDuration(mInternalAllMemPssTime, pw); |
| pw.println(); |
| pw.print(" Internal All Procs (Polling): "); |
| pw.print(mInternalAllPollPssCount); |
| pw.print("x over "); |
| TimeUtils.formatDuration(mInternalAllPollPssTime, pw); |
| pw.println(); |
| pw.print(" External: "); |
| pw.print(mExternalPssCount); |
| pw.print("x over "); |
| TimeUtils.formatDuration(mExternalPssTime, pw); |
| pw.println(); |
| pw.print(" External Slow: "); |
| pw.print(mExternalSlowPssCount); |
| pw.print("x over "); |
| TimeUtils.formatDuration(mExternalSlowPssTime, pw); |
| pw.println(); |
| pw.println(); |
| pw.print(" Start time: "); |
| pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock)); |
| pw.println(); |
| pw.print(" Total uptime: "); |
| TimeUtils.formatDuration( |
| (mRunning ? SystemClock.uptimeMillis() : mTimePeriodEndUptime) |
| - mTimePeriodStartUptime, pw); |
| pw.println(); |
| pw.print(" Total elapsed time: "); |
| TimeUtils.formatDuration( |
| (mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime) |
| - mTimePeriodStartRealtime, pw); |
| boolean partial = true; |
| if ((mFlags&FLAG_SHUTDOWN) != 0) { |
| pw.print(" (shutdown)"); |
| partial = false; |
| } |
| if ((mFlags&FLAG_SYSPROPS) != 0) { |
| pw.print(" (sysprops)"); |
| partial = false; |
| } |
| if ((mFlags&FLAG_COMPLETE) != 0) { |
| pw.print(" (complete)"); |
| partial = false; |
| } |
| if (partial) { |
| pw.print(" (partial)"); |
| } |
| if (mHasSwappedOutPss) { |
| pw.print(" (swapped-out-pss)"); |
| } |
| pw.print(' '); |
| pw.print(mRuntime); |
| pw.println(); |
| } |
| |
| void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix, String prcLabel, |
| int[] screenStates, int[] memStates, int[] procStates, |
| int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) { |
| ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates, |
| procStates, sortProcStates, now, reqPackage, activeOnly); |
| if (procs.size() > 0) { |
| if (header != null) { |
| pw.println(); |
| pw.println(header); |
| } |
| DumpUtils.dumpProcessSummaryLocked(pw, prefix, prcLabel, procs, screenStates, memStates, |
| sortProcStates, now, totalTime); |
| } |
| } |
| |
| public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates, |
| int[] procStates, int sortProcStates[], long now, String reqPackage, |
| boolean activeOnly) { |
| final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>(); |
| final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| mPackages.getMap(); |
| for (int ip=0; ip<pkgMap.size(); ip++) { |
| final String pkgName = pkgMap.keyAt(ip); |
| final SparseArray<LongSparseArray<PackageState>> procs = pkgMap.valueAt(ip); |
| for (int iu=0; iu<procs.size(); iu++) { |
| final LongSparseArray<PackageState> vpkgs = procs.valueAt(iu); |
| final int NVERS = vpkgs.size(); |
| for (int iv=0; iv<NVERS; iv++) { |
| final PackageState state = vpkgs.valueAt(iv); |
| final int NPROCS = state.mProcesses.size(); |
| final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); |
| for (int iproc=0; iproc<NPROCS; iproc++) { |
| final ProcessState proc = state.mProcesses.valueAt(iproc); |
| if (!pkgMatch && !reqPackage.equals(proc.getName())) { |
| continue; |
| } |
| if (activeOnly && !proc.isInUse()) { |
| continue; |
| } |
| foundProcs.add(proc.getCommonProcess()); |
| } |
| } |
| } |
| } |
| ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size()); |
| for (int i=0; i<foundProcs.size(); i++) { |
| ProcessState proc = foundProcs.valueAt(i); |
| if (proc.computeProcessTimeLocked(screenStates, memStates, procStates, now) > 0) { |
| outProcs.add(proc); |
| if (procStates != sortProcStates) { |
| proc.computeProcessTimeLocked(screenStates, memStates, sortProcStates, now); |
| } |
| } |
| } |
| Collections.sort(outProcs, ProcessState.COMPARATOR); |
| return outProcs; |
| } |
| |
| /** |
| * Prints checkin style stats dump. |
| */ |
| public void dumpCheckinLocked(PrintWriter pw, String reqPackage, int section) { |
| final long now = SystemClock.uptimeMillis(); |
| final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| mPackages.getMap(); |
| pw.println("vers,5"); |
| pw.print("period,"); pw.print(mTimePeriodStartClockStr); |
| pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(","); |
| pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime); |
| boolean partial = true; |
| if ((mFlags&FLAG_SHUTDOWN) != 0) { |
| pw.print(",shutdown"); |
| partial = false; |
| } |
| if ((mFlags&FLAG_SYSPROPS) != 0) { |
| pw.print(",sysprops"); |
| partial = false; |
| } |
| if ((mFlags&FLAG_COMPLETE) != 0) { |
| pw.print(",complete"); |
| partial = false; |
| } |
| if (partial) { |
| pw.print(",partial"); |
| } |
| if (mHasSwappedOutPss) { |
| pw.print(",swapped-out-pss"); |
| } |
| pw.println(); |
| pw.print("config,"); pw.println(mRuntime); |
| |
| if ((section & REPORT_PKG_STATS) != 0) { |
| for (int ip = 0; ip < pkgMap.size(); ip++) { |
| final String pkgName = pkgMap.keyAt(ip); |
| if (reqPackage != null && !reqPackage.equals(pkgName)) { |
| continue; |
| } |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| for (int iu = 0; iu < uids.size(); iu++) { |
| final int uid = uids.keyAt(iu); |
| final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu); |
| for (int iv = 0; iv < vpkgs.size(); iv++) { |
| final long vers = vpkgs.keyAt(iv); |
| final PackageState pkgState = vpkgs.valueAt(iv); |
| final int NPROCS = pkgState.mProcesses.size(); |
| final int NSRVS = pkgState.mServices.size(); |
| final int NASCS = pkgState.mAssociations.size(); |
| if ((section & REPORT_PKG_PROC_STATS) != 0) { |
| for (int iproc = 0; iproc < NPROCS; iproc++) { |
| ProcessState proc = pkgState.mProcesses.valueAt(iproc); |
| proc.dumpPackageProcCheckin(pw, pkgName, uid, vers, |
| pkgState.mProcesses.keyAt(iproc), now); |
| } |
| } |
| if ((section & REPORT_PKG_SVC_STATS) != 0) { |
| for (int isvc = 0; isvc < NSRVS; isvc++) { |
| final String serviceName = DumpUtils.collapseString(pkgName, |
| pkgState.mServices.keyAt(isvc)); |
| final ServiceState svc = pkgState.mServices.valueAt(isvc); |
| svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now); |
| } |
| } |
| if ((section & REPORT_PKG_ASC_STATS) != 0) { |
| for (int iasc = 0; iasc < NASCS; iasc++) { |
| final String associationName = DumpUtils.collapseString(pkgName, |
| pkgState.mAssociations.keyAt(iasc)); |
| final AssociationState asc = pkgState.mAssociations.valueAt(iasc); |
| asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if ((section & REPORT_PROC_STATS) != 0) { |
| 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); |
| procState.dumpProcCheckin(pw, procName, uid, now); |
| } |
| } |
| } |
| pw.print("total"); |
| DumpUtils.dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor, mStartTime, now); |
| pw.println(); |
| final int sysMemUsageCount = mSysMemUsage.getKeyCount(); |
| if (sysMemUsageCount > 0) { |
| pw.print("sysmemusage"); |
| for (int i=0; i<sysMemUsageCount; i++) { |
| final int key = mSysMemUsage.getKeyAt(i); |
| final int type = SparseMappingTable.getIdFromKey(key); |
| pw.print(","); |
| DumpUtils.printProcStateTag(pw, type); |
| for (int j=SYS_MEM_USAGE_SAMPLE_COUNT; j<SYS_MEM_USAGE_COUNT; j++) { |
| if (j > SYS_MEM_USAGE_CACHED_MINIMUM) { |
| pw.print(":"); |
| } |
| pw.print(mSysMemUsage.getValue(key, j)); |
| } |
| } |
| } |
| pw.println(); |
| TotalMemoryUseCollection totalMem = new TotalMemoryUseCollection(ALL_SCREEN_ADJ, |
| ALL_MEM_ADJ); |
| computeTotalMemoryUse(totalMem, now); |
| pw.print("weights,"); |
| pw.print(totalMem.totalTime); |
| pw.print(","); |
| pw.print(totalMem.sysMemCachedWeight); |
| pw.print(":"); |
| pw.print(totalMem.sysMemSamples); |
| pw.print(","); |
| pw.print(totalMem.sysMemFreeWeight); |
| pw.print(":"); |
| pw.print(totalMem.sysMemSamples); |
| pw.print(","); |
| pw.print(totalMem.sysMemZRamWeight); |
| pw.print(":"); |
| pw.print(totalMem.sysMemSamples); |
| pw.print(","); |
| pw.print(totalMem.sysMemKernelWeight); |
| pw.print(":"); |
| pw.print(totalMem.sysMemSamples); |
| pw.print(","); |
| pw.print(totalMem.sysMemNativeWeight); |
| pw.print(":"); |
| pw.print(totalMem.sysMemSamples); |
| for (int i=0; i<STATE_COUNT; i++) { |
| pw.print(","); |
| pw.print(totalMem.processStateWeight[i]); |
| pw.print(":"); |
| pw.print(totalMem.processStateSamples[i]); |
| } |
| pw.println(); |
| |
| final int NPAGETYPES = mPageTypeLabels.size(); |
| for (int i=0; i<NPAGETYPES; i++) { |
| pw.print("availablepages,"); |
| pw.print(mPageTypeLabels.get(i)); |
| pw.print(","); |
| pw.print(mPageTypeZones.get(i)); |
| pw.print(","); |
| final int[] sizes = mPageTypeSizes.get(i); |
| final int N = sizes == null ? 0 : sizes.length; |
| for (int j=0; j<N; j++) { |
| if (j != 0) { |
| pw.print(","); |
| } |
| pw.print(sizes[j]); |
| } |
| pw.println(); |
| } |
| } |
| |
| /** |
| * Writes to ProtoOutputStream. |
| */ |
| public void writeToProto(ProtoOutputStream proto, long now, int section) { |
| 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); |
| } |
| |
| final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap(); |
| if ((section & REPORT_PROC_STATS) != 0) { |
| for (int ip = 0; ip < procMap.size(); ip++) { |
| final String procName = procMap.keyAt(ip); |
| final 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); |
| procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName, |
| uid, now); |
| } |
| } |
| } |
| |
| if ((section & REPORT_PKG_STATS) != 0) { |
| final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = |
| mPackages.getMap(); |
| for (int ip = 0; ip < pkgMap.size(); ip++) { |
| final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip); |
| for (int iu = 0; iu < uids.size(); iu++) { |
| final LongSparseArray<PackageState> vers = uids.valueAt(iu); |
| for (int iv = 0; iv < vers.size(); iv++) { |
| final PackageState pkgState = vers.valueAt(iv); |
| pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now, |
| section); |
| } |
| } |
| } |
| } |
| } |
| |
| final public static class ProcessStateHolder { |
| public final long appVersion; |
| public ProcessState state; |
| public PackageState pkg; |
| |
| public ProcessStateHolder(long _appVersion) { |
| appVersion = _appVersion; |
| } |
| } |
| |
| public static final class PackageState { |
| public final ProcessStats mProcessStats; |
| public final ArrayMap<String, ProcessState> mProcesses = new ArrayMap<>(); |
| public final ArrayMap<String, ServiceState> mServices = new ArrayMap<>(); |
| public final ArrayMap<String, AssociationState> mAssociations = new ArrayMap<>(); |
| public final String mPackageName; |
| public final int mUid; |
| public final long mVersionCode; |
| |
| public PackageState(ProcessStats procStats, String packageName, int uid, long versionCode) { |
| mProcessStats = procStats; |
| mUid = uid; |
| mPackageName = packageName; |
| mVersionCode = versionCode; |
| } |
| |
| public AssociationState getAssociationStateLocked(ProcessState proc, String className) { |
| AssociationState as = mAssociations.get(className); |
| if (as != null) { |
| if (DEBUG) Slog.d(TAG, "GETASC: returning existing " + as); |
| if (proc != null) { |
| as.setProcess(proc); |
| } |
| return as; |
| } |
| as = new AssociationState(mProcessStats, this, className, proc.getName(), |
| proc); |
| mAssociations.put(className, as); |
| if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + proc.getName()); |
| return as; |
| } |
| |
| /** |
| * Writes the containing stats into proto, with options to choose smaller sections. |
| */ |
| public void writeToProto(ProtoOutputStream proto, long fieldId, long now, int section) { |
| final long token = proto.start(fieldId); |
| |
| proto.write(ProcessStatsPackageProto.PACKAGE, mPackageName); |
| proto.write(ProcessStatsPackageProto.UID, mUid); |
| proto.write(ProcessStatsPackageProto.VERSION, mVersionCode); |
| |
| if ((section & ProcessStats.REPORT_PKG_PROC_STATS) != 0) { |
| for (int ip = 0; ip < mProcesses.size(); ip++) { |
| final String procName = mProcesses.keyAt(ip); |
| final ProcessState procState = mProcesses.valueAt(ip); |
| procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName, |
| mUid, now); |
| } |
| } |
| |
| if ((section & ProcessStats.REPORT_PKG_SVC_STATS) != 0) { |
| for (int is = 0; is < mServices.size(); is++) { |
| final ServiceState serviceState = mServices.valueAt(is); |
| serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS, |
| now); |
| } |
| } |
| |
| if ((section & ProcessStats.REPORT_PKG_ASC_STATS) != 0) { |
| for (int ia = 0; ia < mAssociations.size(); ia++) { |
| final AssociationState ascState = mAssociations.valueAt(ia); |
| ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS, |
| now); |
| } |
| } |
| |
| proto.end(token); |
| } |
| } |
| |
| public static final class ProcessDataCollection { |
| final int[] screenStates; |
| final int[] memStates; |
| final int[] procStates; |
| |
| public long totalTime; |
| public long numPss; |
| public long minPss; |
| public long avgPss; |
| public long maxPss; |
| public long minUss; |
| public long avgUss; |
| public long maxUss; |
| public long minRss; |
| public long avgRss; |
| public long maxRss; |
| |
| public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) { |
| screenStates = _screenStates; |
| memStates = _memStates; |
| procStates = _procStates; |
| } |
| |
| void print(PrintWriter pw, long overallTime, boolean full) { |
| if (totalTime > overallTime) { |
| pw.print("*"); |
| } |
| DumpUtils.printPercent(pw, (double) totalTime / (double) overallTime); |
| if (numPss > 0) { |
| pw.print(" ("); |
| DebugUtils.printSizeValue(pw, minPss * 1024); |
| pw.print("-"); |
| DebugUtils.printSizeValue(pw, avgPss * 1024); |
| pw.print("-"); |
| DebugUtils.printSizeValue(pw, maxPss * 1024); |
| pw.print("/"); |
| DebugUtils.printSizeValue(pw, minUss * 1024); |
| pw.print("-"); |
| DebugUtils.printSizeValue(pw, avgUss * 1024); |
| pw.print("-"); |
| DebugUtils.printSizeValue(pw, maxUss * 1024); |
| pw.print("/"); |
| DebugUtils.printSizeValue(pw, minRss * 1024); |
| pw.print("-"); |
| DebugUtils.printSizeValue(pw, avgRss * 1024); |
| pw.print("-"); |
| DebugUtils.printSizeValue(pw, maxRss * 1024); |
| if (full) { |
| pw.print(" over "); |
| pw.print(numPss); |
| } |
| pw.print(")"); |
| } |
| } |
| } |
| |
| public static class TotalMemoryUseCollection { |
| final int[] screenStates; |
| final int[] memStates; |
| |
| public TotalMemoryUseCollection(int[] _screenStates, int[] _memStates) { |
| screenStates = _screenStates; |
| memStates = _memStates; |
| } |
| |
| public long totalTime; |
| public long[] processStatePss = new long[STATE_COUNT]; |
| public double[] processStateWeight = new double[STATE_COUNT]; |
| public long[] processStateTime = new long[STATE_COUNT]; |
| public int[] processStateSamples = new int[STATE_COUNT]; |
| public long[] sysMemUsage = new long[SYS_MEM_USAGE_COUNT]; |
| public double sysMemCachedWeight; |
| public double sysMemFreeWeight; |
| public double sysMemZRamWeight; |
| public double sysMemKernelWeight; |
| public double sysMemNativeWeight; |
| public int sysMemSamples; |
| public boolean hasSwappedOutPss; |
| } |
| |
| } |