/* * 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.server.am; import android.os.SystemClock; import android.os.UserHandle; import android.util.ArrayMap; import android.util.SparseArray; import android.util.TimeUtils; import com.android.server.ProcessMap; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; public final class ProcessTracker { public static final int STATE_NOTHING = -1; public static final int STATE_TOP = 0; public static final int STATE_FOREGROUND = 1; public static final int STATE_VISIBLE = 2; public static final int STATE_PERCEPTIBLE = 3; public static final int STATE_BACKUP = 4; public static final int STATE_SERVICE = 5; public static final int STATE_HOME = 6; public static final int STATE_PREVIOUS = 7; public static final int STATE_CACHED = 8; public static final int STATE_COUNT = STATE_CACHED+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; static String[] STATE_NAMES = new String[] { "Top ", "Foreground ", "Visible ", "Perceptible", "Backup ", "Service ", "Home ", "Previous ", "Cached " }; public static final class ProcessState { final String mPackage; final int mUid; final String mName; final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT]; int mCurState = STATE_NOTHING; long mStartTime; long mTmpTotalTime; public ProcessState(String pkg, int uid, String name) { mPackage = pkg; mUid = uid; mName = name; } public void setState(int state, int memFactor, long now) { if (state != STATE_NOTHING) { state += memFactor*STATE_COUNT; } if (mCurState != state) { if (mCurState != STATE_NOTHING) { mDurations[mCurState] += now - mStartTime; } mCurState = state; mStartTime = now; } } } public static final class ServiceState { final long[] mStartedDurations = new long[ADJ_COUNT]; int mStartedCount; int mStartedState = STATE_NOTHING; long mStartedStartTime; final long[] mBoundDurations = new long[ADJ_COUNT]; int mBoundCount; int mBoundState = STATE_NOTHING; long mBoundStartTime; final long[] mExecDurations = new long[ADJ_COUNT]; int mExecCount; int mExecState = STATE_NOTHING; long mExecStartTime; public void setStarted(boolean started, int memFactor, long now) { int state = started ? memFactor : STATE_NOTHING; if (mStartedState != state) { if (mStartedState != STATE_NOTHING) { mStartedDurations[mStartedState] += now - mStartedStartTime; } else if (started) { mStartedCount++; } mStartedState = state; mStartedStartTime = now; } } public void setBound(boolean bound, int memFactor, long now) { int state = bound ? memFactor : STATE_NOTHING; if (mBoundState != state) { if (mBoundState != STATE_NOTHING) { mBoundDurations[mBoundState] += now - mBoundStartTime; } else if (bound) { mBoundCount++; } mBoundState = state; mBoundStartTime = now; } } public void setExecuting(boolean executing, int memFactor, long now) { int state = executing ? memFactor : STATE_NOTHING; if (mExecState != state) { if (mExecState != STATE_NOTHING) { mExecDurations[mExecState] += now - mExecStartTime; } else if (executing) { mExecCount++; } mExecState = state; mExecStartTime = now; } } } public static final class PackageState { final ArrayMap mProcesses = new ArrayMap(); final ArrayMap mServices = new ArrayMap(); final int mUid; public PackageState(int uid) { mUid = uid; } } static final class State { final ProcessMap mPackages = new ProcessMap(); final long[] mMemFactorDurations = new long[ADJ_COUNT]; int mMemFactor = STATE_NOTHING; long mStartTime; } final State mState = new State(); public ProcessTracker() { } private PackageState getPackageStateLocked(String packageName, int uid) { PackageState as = mState.mPackages.get(packageName, uid); if (as != null) { return as; } as = new PackageState(uid); mState.mPackages.put(packageName, uid, as); return as; } public ProcessState getProcessStateLocked(String packageName, int uid, String processName) { final PackageState as = getPackageStateLocked(packageName, uid); ProcessState ps = as.mProcesses.get(processName); if (ps != null) { return ps; } ps = new ProcessState(packageName, uid, processName); as.mProcesses.put(processName, ps); return ps; } public ServiceState getServiceStateLocked(String packageName, int uid, String className) { final PackageState as = getPackageStateLocked(packageName, uid); ServiceState ss = as.mServices.get(className); if (ss != null) { return ss; } ss = new ServiceState(); as.mServices.put(className, ss); return ss; } public boolean setMemFactor(int memFactor, boolean screenOn, long now) { if (screenOn) { memFactor += ADJ_SCREEN_ON; } if (memFactor != mState.mMemFactor) { if (mState.mMemFactor != STATE_NOTHING) { mState.mMemFactorDurations[mState.mMemFactor] += now - mState.mStartTime; } mState.mMemFactor = memFactor; mState.mStartTime = now; ArrayMap> pmap = mState.mPackages.getMap(); for (int i=0; i uids = pmap.valueAt(i); for (int j=0; j services = pkg.mServices; for (int k=0; k collectProcessesLocked(int[] screenStates, int[] memStates, int[] procStates, long now) { ArrayList outProcs = new ArrayList(); ArrayMap> pmap = mState.mPackages.getMap(); for (int ip=0; ip procs = pmap.valueAt(ip); for (int iu=0; iu 0) { outProcs.add(state.mProcesses.valueAt(iproc)); } } } } Collections.sort(outProcs, new Comparator() { @Override public int compare(ProcessState lhs, ProcessState rhs) { if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) { return -1; } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) { return 1; } return 0; } }); return outProcs; } void dumpProcessState(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates, int[] memStates, int[] procStates, long now) { long totalTime = 0; int printedScreen = -1; for (int is=0; is 1) { printScreenLabel(pw, printedScreen != iscreen ? iscreen : STATE_NOTHING); printedScreen = iscreen; } if (memStates.length > 1) { printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING); printedMem = imem; } pw.print(STATE_NAMES[procStates[ip]]); pw.print(": "); TimeUtils.formatDuration(time, pw); pw.println(running); totalTime += time; } } } } if (totalTime != 0) { pw.print(prefix); if (screenStates.length > 1) { printScreenLabel(pw, STATE_NOTHING); } if (memStates.length > 1) { printMemLabel(pw, STATE_NOTHING); } pw.print("TOTAL : "); TimeUtils.formatDuration(totalTime, pw); pw.println(); } } void dumpProcessList(PrintWriter pw, String prefix, ArrayList procs, int[] screenStates, int[] memStates, int[] procStates, long now) { String innerPrefix = prefix + " "; for (int i=procs.size()-1; i>=0; i--) { ProcessState proc = procs.get(i); pw.print(prefix); pw.print(proc.mPackage); pw.print(" / "); UserHandle.formatUid(pw, proc.mUid); pw.print(" / "); pw.print(proc.mName); pw.println(":"); dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now); } } void dumpFilteredProcesses(PrintWriter pw, String header, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now) { ArrayList procs = collectProcessesLocked(screenStates, memStates, procStates, now); if (procs.size() > 0) { pw.println(); pw.println(header); dumpProcessList(pw, prefix, procs, screenStates, memStates, procStates, now); } } public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { final long now = SystemClock.uptimeMillis(); ArrayMap> pmap = mState.mPackages.getMap(); pw.println("Per-Package Process Stats:"); for (int ip=0; ip procs = pmap.valueAt(ip); for (int iu=0; iu