diff options
Diffstat (limited to 'services')
4 files changed, 746 insertions, 138 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index bdfa447..6b13fc7 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -406,7 +406,7 @@ public final class ActivityManagerService extends ActivityManagerNative * Tracking long-term execution of processes to look for abuse and other * bad app behavior. */ - final ProcessTracker mProcessTracker = new ProcessTracker(); + ProcessTracker mProcessTracker; /** * The currently running isolated processes. @@ -1547,6 +1547,7 @@ public final class ActivityManagerService extends ActivityManagerNative m.mContext = context; m.mFactoryTest = factoryTest; m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface()); + m.mProcessTracker = new ProcessTracker(context); m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper); @@ -10173,12 +10174,12 @@ public final class ActivityManagerService extends ActivityManagerNative } String[] newArgs = new String[args.length - opti]; - if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); + System.arraycopy(args, opti, newArgs, 0, args.length - opti); TaskRecord lastTask = null; boolean needSep = false; for (int i=activities.size()-1; i>=0; i--) { - ActivityRecord r = (ActivityRecord)activities.get(i); + ActivityRecord r = activities.get(i); if (needSep) { pw.println(); } diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java index b5d783d..7ea4a32 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/java/com/android/server/am/ProcessList.java @@ -244,7 +244,8 @@ final class ProcessList { } int adjToTrackedState(int adj) { - return adj >= FOREGROUND_APP_ADJ ? mAdjToTrackedState[adj] : ProcessTracker.STATE_NOTHING; + return adj >= FOREGROUND_APP_ADJ + ? mAdjToTrackedState[adj] : ProcessTracker.STATE_PERSISTENT; } private void writeFile(String path, String data) { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index cc0a5a3..e72656f 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -451,8 +451,8 @@ final class ProcessRecord { ProcessList plist) { int state = this == TOP_APP ? ProcessTracker.STATE_TOP : plist.adjToTrackedState(setAdj); - for (int ip=pkgList.size()-1; ip>=0; ip--) { - pkgList.valueAt(ip).setState(state, memFactor, now); + if (pkgList.size() > 0) { + pkgList.valueAt(0).setState(state, memFactor, now, pkgList); } } @@ -461,8 +461,8 @@ final class ProcessRecord { */ public void resetPackageList() { long now = SystemClock.uptimeMillis(); - for (int i=0; i<pkgList.size(); i++) { - pkgList.valueAt(i).setState(ProcessTracker.STATE_NOTHING, 0, now); + if (pkgList.size() > 0) { + pkgList.valueAt(0).setState(ProcessTracker.STATE_NOTHING, 0, now, pkgList); } pkgList.clear(); pkgList.put(info.packageName, baseProcessTracker); diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java index ec8a0b2..8a83412 100644 --- a/services/java/com/android/server/am/ProcessTracker.java +++ b/services/java/com/android/server/am/ProcessTracker.java @@ -16,9 +16,12 @@ package com.android.server.am; +import android.content.Context; +import android.content.pm.PackageManager; import android.os.SystemClock; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.SparseArray; import android.util.TimeUtils; import com.android.server.ProcessMap; @@ -26,20 +29,22 @@ import com.android.server.ProcessMap; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; 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_PERSISTENT = 0; + public static final int STATE_TOP = 1; + public static final int STATE_FOREGROUND = 2; + public static final int STATE_VISIBLE = 3; + public static final int STATE_PERCEPTIBLE = 4; + public static final int STATE_BACKUP = 5; + public static final int STATE_SERVICE = 6; + public static final int STATE_HOME = 7; + public static final int STATE_PREVIOUS = 8; + public static final int STATE_CACHED = 9; public static final int STATE_COUNT = STATE_CACHED+1; public static final int ADJ_NOTHING = -1; @@ -53,12 +58,32 @@ public final class ProcessTracker { 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 " + static final String[] STATE_NAMES = new String[] { + "Persistent ", "Top ", "Foreground ", "Visible ", "Perceptible", + "Backup ", "Service ", "Home ", "Previous ", "Cached " }; + static final String[] ADJ_SCREEN_NAMES_CSV = new String[] { + "off", "on" + }; + + static final String[] ADJ_MEM_NAMES_CSV = new String[] { + "norm", "mod", "low", "crit" + }; + + static final String[] STATE_NAMES_CSV = new String[] { + "pers", "top", "fore", "vis", "percept", + "backup", "service", "home", "prev", "cached" + }; + + static final String CSV_SEP = "\t"; + + final Context mContext; + final State mState = new State(); + public static final class ProcessState { + final State mState; + final ProcessState mCommonProcess; final String mPackage; final int mUid; final String mName; @@ -67,26 +92,96 @@ public final class ProcessTracker { int mCurState = STATE_NOTHING; long mStartTime; + boolean mMultiPackage; + long mTmpTotalTime; - public ProcessState(String pkg, int uid, String name) { + /** + * Create a new top-level process state, for the initial case where there is only + * a single package running in a process. The initial state is not running. + */ + public ProcessState(State state, String pkg, int uid, String name) { + mState = state; + mCommonProcess = null; + mPackage = pkg; + mUid = uid; + mName = name; + } + + /** + * Create a new per-package process state for an existing top-level process + * state. The current running state of the top-level process is also copied, + * marked as started running at 'now'. + */ + public ProcessState(ProcessState commonProcess, String pkg, int uid, String name, + long now) { + mState = commonProcess.mState; + mCommonProcess = commonProcess; mPackage = pkg; mUid = uid; mName = name; + mCurState = commonProcess.mCurState; + mStartTime = now; + } + + ProcessState clone(String pkg, long now) { + ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now); + pnew.add(this, now); + return pnew; } - public void setState(int state, int memFactor, long now) { + public void setState(int state, int memFactor, long now, + ArrayMap<String, ProcessTracker.ProcessState> pkgList) { if (state != STATE_NOTHING) { state += memFactor*STATE_COUNT; } + + if (mCommonProcess != null) { + // First update the common process. + mCommonProcess.setState(state, now); + if (!mCommonProcess.mMultiPackage) { + // This common process is for a single package, so it is shared + // with the per-package state. Nothing more to do. + return; + } + } + + for (int ip=pkgList.size()-1; ip>=0; ip--) { + ProcessState proc = pkgList.valueAt(ip); + if (proc.mMultiPackage) { + // The array map is still pointing to a common process state + // that is now shared across packages. Update it to point to + // the new per-package state. + proc = mState.mPackages.get(pkgList.keyAt(ip), + proc.mUid).mProcesses.get(proc.mName); + if (proc == null) { + throw new IllegalStateException("Didn't create per-package process"); + } + pkgList.setValueAt(ip, proc); + } + proc.setState(state, now); + } + } + + void setState(int state, long now) { if (mCurState != state) { if (mCurState != STATE_NOTHING) { - mDurations[mCurState] += now - mStartTime; + long dur = now - mStartTime; + mDurations[mCurState] += dur; } mCurState = state; mStartTime = now; } } + + void add(ProcessState other, long now) { + for (int i=0; i<(STATE_COUNT*ADJ_COUNT); i++) { + mDurations[i] += other.mDurations[i]; + if (other.mCurState == i) { + mDurations[i] += now - other.mStartTime; + } + } + } } public static final class ServiceState { @@ -157,39 +252,78 @@ public final class ProcessTracker { static final class State { final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>(); + final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>(); final long[] mMemFactorDurations = new long[ADJ_COUNT]; int mMemFactor = STATE_NOTHING; long mStartTime; - } - final State mState = new State(); + PackageState getPackageStateLocked(String packageName, int uid) { + PackageState as = mPackages.get(packageName, uid); + if (as != null) { + return as; + } + as = new PackageState(uid); + mPackages.put(packageName, uid, as); + return as; + } - public ProcessTracker() { - } + ProcessState getProcessStateLocked(String packageName, int uid, String processName) { + final PackageState pkgState = getPackageStateLocked(packageName, uid); + ProcessState ps = pkgState.mProcesses.get(processName); + if (ps != null) { + return ps; + } + ProcessState commonProc = mProcesses.get(processName, uid); + if (commonProc == null) { + commonProc = new ProcessState(this, packageName, uid, processName); + mProcesses.put(processName, uid, commonProc); + } + if (!commonProc.mMultiPackage) { + if (packageName.equals(commonProc.mPackage)) { + // 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; + } else { + // 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.mMultiPackage = true; + // The original package it was created for now needs to point + // to its own copy. + long now = SystemClock.uptimeMillis(); + pkgState.mProcesses.put(commonProc.mPackage, commonProc.clone( + commonProc.mPackage, now)); + ps = new ProcessState(commonProc, packageName, uid, processName, now); + } + } else { + // The common process is for multiple packages, we need to create a + // separate object for the per-package data. + ps = new ProcessState(commonProc, packageName, uid, processName, + SystemClock.uptimeMillis()); + } + pkgState.mProcesses.put(processName, ps); + return ps; + } - private PackageState getPackageStateLocked(String packageName, int uid) { - PackageState as = mState.mPackages.get(packageName, uid); - if (as != null) { - return as; + void reset() { + mPackages.getMap().clear(); + mProcesses.getMap().clear(); + Arrays.fill(mMemFactorDurations, 0); + mMemFactor = STATE_NOTHING; + mStartTime = 0; } - as = new PackageState(uid); - mState.mPackages.put(packageName, uid, as); - return as; + } + + public ProcessTracker(Context context) { + mContext = context; } 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; + return mState.getProcessStateLocked(packageName, uid, processName); } public ServiceState getServiceStateLocked(String packageName, int uid, String className) { - final PackageState as = getPackageStateLocked(packageName, uid); + final PackageState as = mState.getPackageStateLocked(packageName, uid); ServiceState ss = as.mServices.get(className); if (ss != null) { return ss; @@ -252,6 +386,22 @@ public final class ProcessTracker { } } + static private void printScreenLabelCsv(PrintWriter pw, int offset) { + switch (offset) { + case ADJ_NOTHING: + break; + case ADJ_SCREEN_OFF: + pw.print(ADJ_SCREEN_NAMES_CSV[0]); + break; + case ADJ_SCREEN_ON: + pw.print(ADJ_SCREEN_NAMES_CSV[1]); + break; + default: + pw.print("???"); + break; + } + } + static private void printMemLabel(PrintWriter pw, int offset) { switch (offset) { case ADJ_NOTHING: @@ -275,6 +425,16 @@ public final class ProcessTracker { } } + static private void printMemLabelCsv(PrintWriter pw, int offset) { + if (offset >= ADJ_MEM_FACTOR_NORMAL) { + if (offset <= ADJ_MEM_FACTOR_CRITICAL) { + pw.print(ADJ_MEM_NAMES_CSV[offset]); + } else { + pw.print("???"); + } + } + } + static void dumpSingleTime(PrintWriter pw, String prefix, long[] durations, int curState, long curStartTime, long now) { long totalTime = 0; @@ -310,6 +470,43 @@ public final class ProcessTracker { } } + static void dumpSingleTimeCsv(PrintWriter pw, String sep, long[] durations, + int curState, long curStartTime, long now) { + for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) { + for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) { + int state = imem+iscreen; + long time = durations[state]; + if (curState == state) { + time += now - curStartTime; + } + pw.print(sep); + if (time != 0) { + pw.print(time); + } else { + pw.print("0"); + } + } + } + } + + static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName, + int uid, String serviceName, ServiceState svc, int opCount, long[] durations, + int curState, long curStartTime, long now) { + if (opCount <= 0) { + return; + } + pw.print(label); + pw.print(","); + pw.print(packageName); + pw.print(","); + pw.print(uid); + pw.print(","); + pw.print(serviceName); + pw.print(opCount); + dumpSingleTimeCsv(pw, ",", durations, curState, curStartTime, now); + pw.println(); + } + long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates, int[] procStates, long now) { long totalTime = 0; @@ -330,21 +527,33 @@ public final class ProcessTracker { } ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates, - int[] procStates, long now) { - ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(); - ArrayMap<String, SparseArray<PackageState>> pmap = mState.mPackages.getMap(); - for (int ip=0; ip<pmap.size(); ip++) { - SparseArray<PackageState> procs = pmap.valueAt(ip); + int[] procStates, long now, String reqPackage) { + ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>(); + ArrayMap<String, SparseArray<PackageState>> pkgMap = mState.mPackages.getMap(); + for (int ip=0; ip<pkgMap.size(); ip++) { + if (reqPackage != null && !reqPackage.equals(pkgMap.keyAt(ip))) { + continue; + } + SparseArray<PackageState> procs = pkgMap.valueAt(ip); for (int iu=0; iu<procs.size(); iu++) { PackageState state = procs.valueAt(iu); for (int iproc=0; iproc<state.mProcesses.size(); iproc++) { - if (computeProcessTimeLocked(state.mProcesses.valueAt(iproc), - screenStates, memStates, procStates, now) > 0) { - outProcs.add(state.mProcesses.valueAt(iproc)); + ProcessState proc = state.mProcesses.valueAt(iproc); + if (proc.mCommonProcess != null) { + proc = proc.mCommonProcess; } + foundProcs.add(proc); } } } + ArrayList<ProcessState> outProcs = new ArrayList<ProcessState>(foundProcs.size()); + for (int i=0; i<foundProcs.size(); i++) { + ProcessState proc = foundProcs.valueAt(i); + if (computeProcessTimeLocked(proc, screenStates, memStates, + procStates, now) > 0) { + outProcs.add(proc); + } + } Collections.sort(outProcs, new Comparator<ProcessState>() { @Override public int compare(ProcessState lhs, ProcessState rhs) { @@ -376,7 +585,6 @@ public final class ProcessTracker { time += now - proc.mStartTime; running = " (running)"; } - totalTime += time; if (time != 0) { pw.print(prefix); if (screenStates.length > 1) { @@ -409,26 +617,119 @@ public final class ProcessTracker { } } + void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates, + int[] memStates, int[] procStates) { + final int NS = screenStates != null ? screenStates.length : 1; + final int NM = memStates != null ? memStates.length : 1; + final int NP = procStates != null ? procStates.length : 1; + for (int is=0; is<NS; is++) { + for (int im=0; im<NM; im++) { + for (int ip=0; ip<NP; ip++) { + pw.print(sep); + boolean printed = false; + if (screenStates != null && screenStates.length > 1) { + printScreenLabelCsv(pw, screenStates[is]); + printed = true; + } + if (memStates != null && memStates.length > 1) { + if (printed) { + pw.print("-"); + } + printMemLabelCsv(pw, memStates[im]); + printed = true; + } + if (procStates != null && procStates.length > 1) { + if (printed) { + pw.print("-"); + } + pw.print(STATE_NAMES_CSV[procStates[ip]]); + } + } + } + } + } + + void dumpProcessStateCsv(PrintWriter pw, ProcessState proc, + boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, + boolean sepProcStates, int[] procStates, long now) { + final int NSS = sepScreenStates ? screenStates.length : 1; + final int NMS = sepMemStates ? memStates.length : 1; + final int NPS = sepProcStates ? procStates.length : 1; + for (int iss=0; iss<NSS; iss++) { + for (int ims=0; ims<NMS; ims++) { + for (int ips=0; ips<NPS; ips++) { + final int vsscreen = sepScreenStates ? screenStates[iss] : 0; + final int vsmem = sepMemStates ? memStates[ims] : 0; + final int vsproc = sepProcStates ? procStates[ips] : 0; + final int NSA = sepScreenStates ? 1 : screenStates.length; + final int NMA = sepMemStates ? 1 : memStates.length; + final int NPA = sepProcStates ? 1 : procStates.length; + long totalTime = 0; + for (int isa=0; isa<NSA; isa++) { + for (int ima=0; ima<NMA; ima++) { + for (int ipa=0; ipa<NPA; ipa++) { + final int vascreen = sepScreenStates ? 0 : screenStates[isa]; + final int vamem = sepMemStates ? 0 : memStates[ima]; + final int vaproc = sepProcStates ? 0 : procStates[ipa]; + final int bucket = ((vsscreen + vascreen + vsmem + vamem) + * STATE_COUNT) + vsproc + vaproc; + totalTime += proc.mDurations[bucket]; + if (proc.mCurState == bucket) { + totalTime += now - proc.mStartTime; + } + } + } + } + pw.print(CSV_SEP); + if (totalTime != 0) { + pw.print(totalTime); + } else { + pw.print("0"); + } + } + } + } + } + void dumpProcessList(PrintWriter pw, String prefix, ArrayList<ProcessState> 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(proc.mName); pw.print(" / "); UserHandle.formatUid(pw, proc.mUid); - pw.print(" / "); - pw.print(proc.mName); pw.println(":"); dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now); } } + void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs, + boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, + boolean sepProcStates, int[] procStates, long now) { + pw.print("process"); + pw.print(CSV_SEP); + pw.print("uid"); + dumpStateHeadersCsv(pw, CSV_SEP, sepScreenStates ? screenStates : null, + sepMemStates ? memStates : null, + sepProcStates ? procStates : null); + pw.println(); + for (int i=procs.size()-1; i>=0; i--) { + ProcessState proc = procs.get(i); + pw.print(proc.mName); + pw.print(CSV_SEP); + UserHandle.formatUid(pw, proc.mUid); + dumpProcessStateCsv(pw, proc, sepScreenStates, screenStates, + sepMemStates, memStates, sepProcStates, procStates, now); + pw.println(); + } + } + void dumpFilteredProcesses(PrintWriter pw, String header, String prefix, - int[] screenStates, int[] memStates, int[] procStates, long now) { + int[] screenStates, int[] memStates, int[] procStates, long now, String reqPackage) { ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates, - procStates, now); + procStates, now, reqPackage); if (procs.size() > 0) { pw.println(); pw.println(header); @@ -436,100 +737,405 @@ public final class ProcessTracker { } } + boolean dumpFilteredProcessesCsv(PrintWriter pw, String header, + boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, + boolean sepProcStates, int[] procStates, long now, String reqPackage) { + ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates, + procStates, now, reqPackage); + if (procs.size() > 0) { + if (header != null) { + pw.println(header); + } + dumpProcessListCsv(pw, procs, sepScreenStates, screenStates, + sepMemStates, memStates, sepProcStates, procStates, now); + return true; + } + return false; + } + + void dumpAllProcessState(PrintWriter pw, String prefix, boolean isCheckin, + ProcessState proc, long now) { + long totalTime = 0; + int printedScreen = -1; + for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) { + int printedMem = -1; + for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) { + for (int is=0; is<STATE_NAMES.length; is++) { + int bucket = is+(STATE_COUNT*(imem+iscreen)); + long time = proc.mDurations[bucket]; + String running = ""; + if (proc.mCurState == bucket) { + time += now - proc.mStartTime; + running = " (running)"; + } + if (!isCheckin) { + if (time != 0) { + pw.print(prefix); + printScreenLabel(pw, printedScreen != iscreen + ? iscreen : STATE_NOTHING); + printedScreen = iscreen; + printMemLabel(pw, printedMem != imem + ? imem : STATE_NOTHING); + printedMem = imem; + pw.print(STATE_NAMES[is]); pw.print(": "); + TimeUtils.formatDuration(time, pw); pw.println(running); + totalTime += time; + } + } else { + pw.print(","); + if (time != 0) { + pw.print(time); + } else { + pw.print("0"); + } + } + } + } + } + if (!isCheckin) { + if (totalTime != 0) { + pw.print(prefix); + printScreenLabel(pw, STATE_NOTHING); + printMemLabel(pw, STATE_NOTHING); + pw.print("TOTAL : "); + TimeUtils.formatDuration(totalTime, pw); + pw.println(); + } + } else { + pw.println(); + } + } + + static int[] parseStateList(String[] states, int mult, String arg, boolean[] outSep, + String[] outError) { + ArrayList<Integer> res = new ArrayList<Integer>(); + int lastPos = 0; + for (int i=0; i<=arg.length(); i++) { + char c = i < arg.length() ? arg.charAt(i) : 0; + if (c != ',' && c != '+' && c != ' ' && c != 0) { + continue; + } + boolean isSep = c == ','; + if (lastPos == 0) { + // We now know the type of op. + outSep[0] = isSep; + } else if (c != 0 && outSep[0] != isSep) { + outError[0] = "inconsistent separators (can't mix ',' with '+')"; + return null; + } + if (lastPos < (i-1)) { + String str = arg.substring(lastPos, i); + for (int j=0; j<states.length; j++) { + if (str.equals(states[j])) { + res.add(j); + str = null; + break; + } + } + if (str != null) { + outError[0] = "invalid word \"" + str + "\""; + return null; + } + } + lastPos = i + 1; + } + + int[] finalRes = new int[res.size()]; + for (int i=0; i<res.size(); i++) { + finalRes[i] = res.get(i) * mult; + } + return finalRes; + } + + private void dumpHelp(PrintWriter pw) { + pw.println("Process stats (procstats) dump options:"); + pw.println(" [--checkin|--csv] [csv-screen] [csv-proc] [csv-mem]"); + pw.println(" [--reset] [-h] [<package.name>]"); + pw.println(" --checkin: format output for a checkin report."); + pw.println(" --csv: output data suitable for putting in a spreadsheet."); + pw.println(" --csv-screen: on, off."); + pw.println(" --csv-mem: norm, mod, low, crit."); + pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,"); + pw.println(" service, home, prev, cached"); + pw.println(" --reset: reset the stats, clearing all current data."); + pw.println(" -h: print this help text."); + pw.println(" <package.name>: optional name of package to filter output by."); + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { final long now = SystemClock.uptimeMillis(); - ArrayMap<String, SparseArray<PackageState>> pmap = mState.mPackages.getMap(); - pw.println("Per-Package Process Stats:"); - for (int ip=0; ip<pmap.size(); ip++) { - String procName = pmap.keyAt(ip); - SparseArray<PackageState> procs = pmap.valueAt(ip); - for (int iu=0; iu<procs.size(); iu++) { - int uid = procs.keyAt(iu); - PackageState state = procs.valueAt(iu); - pw.print(" * "); pw.print(procName); pw.print(" / "); - UserHandle.formatUid(pw, uid); pw.println(":"); - for (int iproc=0; iproc<state.mProcesses.size(); iproc++) { - pw.print(" Process "); - pw.print(state.mProcesses.keyAt(iproc)); - pw.println(":"); - long totalTime = 0; - ProcessState proc = state.mProcesses.valueAt(iproc); - int printedScreen = -1; - for (int iscreen=0; iscreen<ADJ_COUNT; iscreen+=ADJ_SCREEN_MOD) { - int printedMem = -1; - for (int imem=0; imem<ADJ_MEM_FACTOR_COUNT; imem++) { - for (int is=0; is<STATE_NAMES.length; is++) { - int bucket = is+(STATE_COUNT*(imem+iscreen)); - long time = proc.mDurations[bucket]; - String running = ""; - if (proc.mCurState == bucket) { - time += now - proc.mStartTime; - running = " (running)"; - } - if (time != 0) { - pw.print(" "); - printScreenLabel(pw, printedScreen != iscreen - ? iscreen : STATE_NOTHING); - printedScreen = iscreen; - printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING); - printedMem = imem; - pw.print(STATE_NAMES[is]); pw.print(": "); - TimeUtils.formatDuration(time, pw); pw.println(running); - totalTime += time; - } - } - } + + boolean isCheckin = false; + boolean isCsv = false; + String reqPackage = null; + boolean csvSepScreenStats = false; + int[] csvScreenStats = new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}; + boolean csvSepMemStats = false; + int[] csvMemStats = new int[] {ADJ_MEM_FACTOR_CRITICAL}; + boolean csvSepProcStats = true; + int[] csvProcStats = new int[] { + STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, + STATE_PREVIOUS, STATE_CACHED }; + if (args != null) { + for (int i=0; i<args.length; i++) { + String arg = args[i]; + if ("--checkin".equals(arg)) { + isCheckin = true; + } else if ("--csv".equals(arg)) { + isCsv = true; + } else if ("--csv-screen".equals(arg)) { + i++; + if (i >= args.length) { + pw.println("Error: argument required for --csv-screen"); + dumpHelp(pw); + return; } - if (totalTime != 0) { - pw.print(" "); - printScreenLabel(pw, STATE_NOTHING); - printMemLabel(pw, STATE_NOTHING); - pw.print("TOTAL : "); - TimeUtils.formatDuration(totalTime, pw); - pw.println(); + boolean[] sep = new boolean[1]; + String[] error = new String[1]; + csvScreenStats = parseStateList(ADJ_SCREEN_NAMES_CSV, ADJ_SCREEN_MOD, + args[i], sep, error); + if (csvScreenStats == null) { + pw.println("Error in \"" + args[i] + "\": " + error[0]); + dumpHelp(pw); + return; + } + csvSepScreenStats = sep[0]; + } else if ("--csv-mem".equals(arg)) { + i++; + if (i >= args.length) { + pw.println("Error: argument required for --csv-mem"); + dumpHelp(pw); + return; + } + boolean[] sep = new boolean[1]; + String[] error = new String[1]; + csvMemStats = parseStateList(ADJ_MEM_NAMES_CSV, 1, args[i], sep, error); + if (csvMemStats == null) { + pw.println("Error in \"" + args[i] + "\": " + error[0]); + dumpHelp(pw); + return; + } + csvSepMemStats = sep[0]; + } else if ("--csv-proc".equals(arg)) { + i++; + if (i >= args.length) { + pw.println("Error: argument required for --csv-proc"); + dumpHelp(pw); + return; + } + boolean[] sep = new boolean[1]; + String[] error = new String[1]; + csvProcStats = parseStateList(STATE_NAMES_CSV, 1, args[i], sep, error); + if (csvProcStats == null) { + pw.println("Error in \"" + args[i] + "\": " + error[0]); + dumpHelp(pw); + return; + } + csvSepProcStats = sep[0]; + } else if ("--reset".equals(arg)) { + mState.reset(); + pw.println("Process stats reset."); + return; + } else if ("-h".equals(arg)) { + dumpHelp(pw); + return; + } else if ("-a".equals(arg)) { + // ignore + } else if (arg.length() > 0 && arg.charAt(0) == '-'){ + pw.println("Unknown option: " + arg); + dumpHelp(pw); + return; + } else { + // Not an option, last argument must be a package name. + try { + mContext.getPackageManager().getPackageUid(arg, + UserHandle.getCallingUserId()); + reqPackage = arg; + } catch (PackageManager.NameNotFoundException e) { + pw.println("Unknown package: " + arg); + dumpHelp(pw); + return; } } - for (int isvc=0; isvc<state.mServices.size(); isvc++) { - pw.print(" Service "); - pw.print(state.mServices.keyAt(isvc)); - pw.println(":"); - ServiceState svc = state.mServices.valueAt(isvc); - if (svc.mStartedCount != 0) { - pw.print(" Started op count "); pw.print(svc.mStartedCount); - pw.println(":"); - dumpSingleTime(pw, " ", svc.mStartedDurations, svc.mStartedState, - svc.mStartedStartTime, now); + } + } + + if (isCsv) { + pw.print("Processes running summed over"); + if (!csvSepScreenStats) { + for (int i=0; i<csvScreenStats.length; i++) { + pw.print(" "); + printScreenLabelCsv(pw, csvScreenStats[i]); + } + } + if (!csvSepMemStats) { + for (int i=0; i<csvMemStats.length; i++) { + pw.print(" "); + printMemLabelCsv(pw, csvMemStats[i]); + } + } + if (!csvSepProcStats) { + for (int i=0; i<csvProcStats.length; i++) { + pw.print(" "); + pw.print(STATE_NAMES_CSV[csvProcStats[i]]); + } + } + pw.println(); + dumpFilteredProcessesCsv(pw, null, + csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats, + csvSepProcStats, csvProcStats, now, reqPackage); + /* + dumpFilteredProcessesCsv(pw, "Processes running while critical mem:", + false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + true, new int[] {ADJ_MEM_FACTOR_CRITICAL}, + true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, + STATE_PREVIOUS, STATE_CACHED}, + now, reqPackage); + dumpFilteredProcessesCsv(pw, "Processes running over all mem:", + false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW, + ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE}, + true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, + STATE_PREVIOUS, STATE_CACHED}, + now, reqPackage); + */ + return; + } + + ArrayMap<String, SparseArray<PackageState>> pkgMap = mState.mPackages.getMap(); + boolean printedHeader = false; + if (isCheckin) { + pw.println("vers,1"); + } + for (int ip=0; ip<pkgMap.size(); ip++) { + String pkgName = pkgMap.keyAt(ip); + if (reqPackage != null && !reqPackage.equals(pkgName)) { + continue; + } + SparseArray<PackageState> uids = pkgMap.valueAt(ip); + for (int iu=0; iu<uids.size(); iu++) { + int uid = uids.keyAt(iu); + PackageState state = uids.valueAt(iu); + final int NPROCS = state.mProcesses.size(); + final int NSRVS = state.mServices.size(); + if (!isCheckin) { + if (NPROCS > 0 || NSRVS > 0) { + if (!printedHeader) { + pw.println("Per-Package Process Stats:"); + printedHeader = true; + } + pw.print(" * "); pw.print(pkgName); pw.print(" / "); + UserHandle.formatUid(pw, uid); pw.println(":"); } - if (svc.mBoundCount != 0) { - pw.print(" Bound op count "); pw.print(svc.mBoundCount); + } + for (int iproc=0; iproc<NPROCS; iproc++) { + if (!isCheckin) { + pw.print(" Process "); + pw.print(state.mProcesses.keyAt(iproc)); pw.println(":"); - dumpSingleTime(pw, " ", svc.mBoundDurations, svc.mBoundState, - svc.mBoundStartTime, now); + } else { + pw.print("pkgproc,"); + pw.print(pkgName); + pw.print(","); + pw.print(uid); + pw.print(","); + pw.print(state.mProcesses.keyAt(iproc)); } - if (svc.mExecCount != 0) { - pw.print(" Executing op count "); pw.print(svc.mExecCount); + dumpAllProcessState(pw, " ", isCheckin, + state.mProcesses.valueAt(iproc), now); + } + for (int isvc=0; isvc<NSRVS; isvc++) { + if (!isCheckin) { + pw.print(" Service "); + pw.print(state.mServices.keyAt(isvc)); pw.println(":"); - dumpSingleTime(pw, " ", svc.mExecDurations, svc.mExecState, + ServiceState svc = state.mServices.valueAt(isvc); + if (svc.mStartedCount != 0) { + pw.print(" Started op count "); pw.print(svc.mStartedCount); + pw.println(":"); + dumpSingleTime(pw, " ", svc.mStartedDurations, svc.mStartedState, + svc.mStartedStartTime, now); + } + if (svc.mBoundCount != 0) { + pw.print(" Bound op count "); pw.print(svc.mBoundCount); + pw.println(":"); + dumpSingleTime(pw, " ", svc.mBoundDurations, svc.mBoundState, + svc.mBoundStartTime, now); + } + if (svc.mExecCount != 0) { + pw.print(" Executing op count "); pw.print(svc.mExecCount); + pw.println(":"); + dumpSingleTime(pw, " ", svc.mExecDurations, svc.mExecState, + svc.mExecStartTime, now); + } + } else { + String serviceName = state.mServices.keyAt(isvc); + ServiceState svc = state.mServices.valueAt(isvc); + dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, serviceName, + svc, svc.mStartedCount, svc.mStartedDurations, svc.mStartedState, + svc.mStartedStartTime, now); + dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, serviceName, + svc, svc.mBoundCount, svc.mBoundDurations, svc.mBoundState, + svc.mBoundStartTime, now); + dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, serviceName, + svc, svc.mExecCount, svc.mExecDurations, svc.mExecState, svc.mExecStartTime, now); } } } } - dumpFilteredProcesses(pw, "Processes running while critical mem:", " ", - new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, - new int[] {ADJ_MEM_FACTOR_CRITICAL}, - new int[] {STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, - STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, - now); - dumpFilteredProcesses(pw, "Processes running while low mem:", " ", - new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, - new int[] {ADJ_MEM_FACTOR_LOW}, - new int[] {STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, - STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, - now); - pw.println(); - pw.println("Run time Stats:"); - dumpSingleTime(pw, " ", mState.mMemFactorDurations, mState.mMemFactor, - mState.mStartTime, now); + + if (!isCheckin) { + dumpFilteredProcesses(pw, "Processes running while critical mem:", " ", + new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + new int[] {ADJ_MEM_FACTOR_CRITICAL}, + new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, + now, reqPackage); + dumpFilteredProcesses(pw, "Processes running while low mem:", " ", + new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + new int[] {ADJ_MEM_FACTOR_LOW}, + new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, + now, reqPackage); + dumpFilteredProcesses(pw, "Processes running while moderate mem:", " ", + new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + new int[] {ADJ_MEM_FACTOR_MODERATE}, + new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, + now, reqPackage); + dumpFilteredProcesses(pw, "Processes running while normal mem:", " ", + new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON}, + new int[] {ADJ_MEM_FACTOR_NORMAL}, + new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE, + STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS}, + now, reqPackage); + pw.println(); + pw.println("Run time Stats:"); + dumpSingleTime(pw, " ", mState.mMemFactorDurations, mState.mMemFactor, + mState.mStartTime, now); + } else { + ArrayMap<String, SparseArray<ProcessState>> procMap = mState.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++) { + int uid = uids.keyAt(iu); + ProcessState state = uids.valueAt(iu); + pw.print("proc,"); + pw.print(procName); + pw.print(","); + pw.print(uid); + dumpAllProcessState(pw, " ", isCheckin, state, now); + } + } + pw.print("total,"); + dumpSingleTimeCsv(pw, ",", mState.mMemFactorDurations, mState.mMemFactor, + mState.mStartTime, now); + pw.println(); + } } } |