summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Binder.java17
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java (renamed from core/java/com/android/internal/os/ProcessStats.java)78
-rw-r--r--packages/SystemUI/src/com/android/systemui/LoadAverageService.java18
-rw-r--r--services/java/com/android/internal/app/ProcessStats.java2437
-rw-r--r--services/java/com/android/server/am/ActiveServices.java31
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java141
-rw-r--r--services/java/com/android/server/am/ActivityStack.java10
-rw-r--r--services/java/com/android/server/am/ActivityStackSupervisor.java2
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java2
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java15
-rw-r--r--services/java/com/android/server/am/ProcessStatsService.java714
-rw-r--r--services/java/com/android/server/am/ProcessTracker.java3126
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java7
13 files changed, 3320 insertions, 3278 deletions
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 7b91418..4627c88 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -296,7 +296,21 @@ public class Binder implements IBinder {
disabled = sDumpDisabled;
}
if (disabled == null) {
- dump(fd, pw, args);
+ try {
+ dump(fd, pw, args);
+ } catch (SecurityException e) {
+ pw.println();
+ pw.println("Security exception: " + e.getMessage());
+ throw e;
+ } catch (Throwable e) {
+ // Unlike usual calls, in this case if an exception gets thrown
+ // back to us we want to print it back in to the dump data, since
+ // that is where the caller expects all interesting information to
+ // go.
+ pw.println();
+ pw.println("Exception occurred while dumping:");
+ e.printStackTrace(pw);
+ }
} else {
pw.println(sDumpDisabled);
}
@@ -443,7 +457,6 @@ final class BinderProxy implements IBinder {
data.writeStringArray(args);
try {
transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
- reply.readException();
} finally {
data.recycle();
reply.recycle();
diff --git a/core/java/com/android/internal/os/ProcessStats.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 874bc0e..c092807 100644
--- a/core/java/com/android/internal/os/ProcessStats.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -34,11 +34,11 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;
-public class ProcessStats {
+public class ProcessCpuTracker {
private static final String TAG = "ProcessStats";
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG || false;
-
+
private static final int[] PROCESS_STATS_FORMAT = new int[] {
PROC_SPACE_TERM,
PROC_SPACE_TERM|PROC_PARENS,
@@ -61,7 +61,7 @@ public class ProcessStats {
static final int PROCESS_STAT_MAJOR_FAULTS = 1;
static final int PROCESS_STAT_UTIME = 2;
static final int PROCESS_STAT_STIME = 3;
-
+
/** Stores user time and system time in 100ths of a second. */
private final long[] mProcessStatsData = new long[4];
/** Stores user time and system time in 100ths of a second. */
@@ -123,14 +123,14 @@ public class ProcessStats {
private final float[] mLoadAverageData = new float[3];
private final boolean mIncludeThreads;
-
+
private float mLoad1 = 0;
private float mLoad5 = 0;
private float mLoad15 = 0;
-
+
private long mCurrentSampleTime;
private long mLastSampleTime;
-
+
private long mCurrentSampleRealTime;
private long mLastSampleRealTime;
@@ -149,7 +149,7 @@ public class ProcessStats {
private int[] mCurPids;
private int[] mCurThreadPids;
-
+
private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
private boolean mWorkingProcsSorted;
@@ -202,12 +202,12 @@ public class ProcessStats {
public long base_majfaults;
public int rel_minfaults;
public int rel_majfaults;
-
+
public boolean active;
public boolean working;
public boolean added;
public boolean removed;
-
+
Stats(int _pid, int parentPid, boolean includeThreads) {
pid = _pid;
if (parentPid < 0) {
@@ -256,30 +256,30 @@ public class ProcessStats {
};
- public ProcessStats(boolean includeThreads) {
+ public ProcessCpuTracker(boolean includeThreads) {
mIncludeThreads = includeThreads;
}
-
+
public void onLoadChanged(float load1, float load5, float load15) {
}
-
+
public int onMeasureProcessName(String name) {
return 0;
}
-
+
public void init() {
if (DEBUG) Slog.v(TAG, "Init: " + this);
mFirst = true;
update();
}
-
+
public void update() {
if (DEBUG) Slog.v(TAG, "Update: " + this);
mLastSampleTime = mCurrentSampleTime;
mCurrentSampleTime = SystemClock.uptimeMillis();
mLastSampleRealTime = mCurrentSampleRealTime;
mCurrentSampleRealTime = SystemClock.elapsedRealtime();
-
+
final long[] sysCpu = mSystemCpuData;
if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
null, sysCpu, null)) {
@@ -339,11 +339,11 @@ public class ProcessStats {
mWorkingProcsSorted = false;
mFirst = false;
- }
-
+ }
+
private int[] collectStats(String statsFile, int parentPid, boolean first,
int[] curPids, ArrayList<Stats> allProcs) {
-
+
int[] pids = Process.getPids(statsFile, curPids);
int NP = (pids == null) ? 0 : pids.length;
int NS = allProcs.size();
@@ -355,7 +355,7 @@ public class ProcessStats {
break;
}
Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
-
+
if (st != null && st.pid == pid) {
// Update an existing process...
st.added = false;
@@ -373,7 +373,7 @@ public class ProcessStats {
PROCESS_STATS_FORMAT, null, procStats, null)) {
continue;
}
-
+
final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
final long utime = procStats[PROCESS_STAT_UTIME];
@@ -423,7 +423,7 @@ public class ProcessStats {
continue;
}
-
+
if (st == null || st.pid > pid) {
// We have a new process!
st = new Stats(pid, parentPid, mIncludeThreads);
@@ -477,7 +477,7 @@ public class ProcessStats {
if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
+ " utime=" + st.base_utime + " stime=" + st.base_stime
+ " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
-
+
st.rel_utime = 0;
st.rel_stime = 0;
st.rel_minfaults = 0;
@@ -488,7 +488,7 @@ public class ProcessStats {
}
continue;
}
-
+
// This process has gone away!
st.rel_utime = 0;
st.rel_stime = 0;
@@ -520,7 +520,7 @@ public class ProcessStats {
NS--;
if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
}
-
+
return pids;
}
@@ -607,27 +607,27 @@ public class ProcessStats {
final public int getLastUserTime() {
return mRelUserTime;
}
-
+
final public int getLastSystemTime() {
return mRelSystemTime;
}
-
+
final public int getLastIoWaitTime() {
return mRelIoWaitTime;
}
-
+
final public int getLastIrqTime() {
return mRelIrqTime;
}
-
+
final public int getLastSoftIrqTime() {
return mRelSoftIrqTime;
}
-
+
final public int getLastIdleTime() {
return mRelIdleTime;
}
-
+
final public float getTotalCpuPercent() {
int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
if (denom <= 0) {
@@ -635,7 +635,7 @@ public class ProcessStats {
}
return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
}
-
+
final void buildWorkingProcs() {
if (!mWorkingProcsSorted) {
mWorkingProcs.clear();
@@ -678,7 +678,7 @@ public class ProcessStats {
final public Stats getWorkingStats(int index) {
return mWorkingProcs.get(index);
}
-
+
final public String printCurrentLoad() {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 128);
@@ -694,10 +694,10 @@ public class ProcessStats {
final public String printCurrentState(long now) {
buildWorkingProcs();
-
+
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
-
+
pw.print("CPU usage from ");
if (now > mLastSampleTime) {
pw.print(now-mLastSampleTime);
@@ -720,10 +720,10 @@ public class ProcessStats {
pw.print("% awake");
}
pw.println(":");
-
+
final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
+ mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
-
+
if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
+ (mCurrentSampleTime-mLastSampleTime));
@@ -744,14 +744,14 @@ public class ProcessStats {
}
}
}
-
+
printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
pw.flush();
return sw.toString();
}
-
+
private void printRatio(PrintWriter pw, long numerator, long denominator) {
long thousands = (numerator*1000)/denominator;
long hundreds = thousands/10;
@@ -812,7 +812,7 @@ public class ProcessStats {
}
pw.println();
}
-
+
private String readFile(String file, char endChar) {
// Permit disk reads here, as /proc/meminfo isn't really "on
// disk" and should be fast. TODO: make BlockGuard ignore
diff --git a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
index efbee5b..610e42b 100644
--- a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
+++ b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
@@ -29,18 +29,18 @@ import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
-import com.android.internal.os.ProcessStats;
+import com.android.internal.os.ProcessCpuTracker;
public class LoadAverageService extends Service {
private View mView;
- private static final class Stats extends ProcessStats {
+ private static final class CpuTracker extends ProcessCpuTracker {
String mLoadText;
int mLoadWidth;
private final Paint mPaint;
- Stats(Paint paint) {
+ CpuTracker(Paint paint) {
super(false);
mPaint = paint;
}
@@ -70,7 +70,7 @@ public class LoadAverageService extends Service {
}
};
- private final Stats mStats;
+ private final CpuTracker mStats;
private Paint mLoadPaint;
private Paint mAddedPaint;
@@ -150,7 +150,7 @@ public class LoadAverageService extends Service {
float descent = mLoadPaint.descent();
mFH = (int)(descent - mAscent + .5f);
- mStats = new Stats(mLoadPaint);
+ mStats = new CpuTracker(mLoadPaint);
mStats.init();
updateDisplay();
}
@@ -179,7 +179,7 @@ public class LoadAverageService extends Service {
final int W = mNeededWidth;
final int RIGHT = getWidth()-1;
- final Stats stats = mStats;
+ final CpuTracker stats = mStats;
final int userTime = stats.getLastUserTime();
final int systemTime = stats.getLastSystemTime();
final int iowaitTime = stats.getLastIoWaitTime();
@@ -226,7 +226,7 @@ public class LoadAverageService extends Service {
int N = stats.countWorkingStats();
for (int i=0; i<N; i++) {
- Stats.Stats st = stats.getWorkingStats(i);
+ CpuTracker.Stats st = stats.getWorkingStats(i);
y += mFH;
top += mFH;
bottom += mFH;
@@ -259,12 +259,12 @@ public class LoadAverageService extends Service {
}
void updateDisplay() {
- final Stats stats = mStats;
+ final CpuTracker stats = mStats;
final int NW = stats.countWorkingStats();
int maxWidth = stats.mLoadWidth;
for (int i=0; i<NW; i++) {
- Stats.Stats st = stats.getWorkingStats(i);
+ CpuTracker.Stats st = stats.getWorkingStats(i);
if (st.nameWidth > maxWidth) {
maxWidth = st.nameWidth;
}
diff --git a/services/java/com/android/internal/app/ProcessStats.java b/services/java/com/android/internal/app/ProcessStats.java
new file mode 100644
index 0000000..e916b56
--- /dev/null
+++ b/services/java/com/android/internal/app/ProcessStats.java
@@ -0,0 +1,2437 @@
+/*
+ * 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;
+
+import android.os.Parcel;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import android.webkit.WebViewFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.ProcessMap;
+import dalvik.system.VMRuntime;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Objects;
+
+final public class ProcessStats {
+ static final String TAG = "ProcessStats";
+ static final boolean DEBUG = false;
+
+ 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_HEAVY_WEIGHT = 5;
+ public static final int STATE_SERVICE = 6;
+ public static final int STATE_SERVICE_RESTARTING = 7;
+ public static final int STATE_RECEIVER = 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_COUNT = PSS_USS_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;
+
+ static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, ADJ_MEM_FACTOR_MODERATE,
+ ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
+ static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
+ static final int[] NON_CACHED_PROC_STATES = new int[] { STATE_PERSISTENT,
+ STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
+ STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HOME
+ };
+
+ // Map from process states to the states we track.
+ static final int[] PROCESS_STATE_TO_STATE = new int[] {
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+ STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
+ STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
+ STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
+ STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER
+ STATE_HOME, // ActivityManager.PROCESS_STATE_HOME
+ STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+ STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+ STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
+ };
+
+ public static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
+ STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+ STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
+ STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
+ STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
+ };
+
+ static final String[] STATE_NAMES = new String[] {
+ "Persistent", "Top ", "Imp Fg ", "Imp Bg ",
+ "Backup ", "Heavy Wght", "Service ", "Service Rs",
+ "Receiver ", "Home ",
+ "Last Act ", "Cch Act ", "Cch CliAct", "Cch Empty "
+ };
+
+ public static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
+ "off", "on"
+ };
+
+ public static final String[] ADJ_MEM_NAMES_CSV = new String[] {
+ "norm", "mod", "low", "crit"
+ };
+
+ public static final String[] STATE_NAMES_CSV = new String[] {
+ "pers", "top", "impfg", "impbg", "backup", "heavy",
+ "service", "service-rs", "receiver", "home", "lastact",
+ "cch-activity", "cch-aclient", "cch-empty"
+ };
+
+ static final String[] ADJ_SCREEN_TAGS = new String[] {
+ "0", "1"
+ };
+
+ static final String[] ADJ_MEM_TAGS = new String[] {
+ "n", "m", "l", "c"
+ };
+
+ static final String[] STATE_TAGS = new String[] {
+ "p", "t", "f", "b", "u", "w",
+ "s", "x", "r", "h", "l", "a", "c", "e"
+ };
+
+ static final String CSV_SEP = "\t";
+
+ // Current version of the parcel format.
+ private static final int PARCEL_VERSION = 9;
+ // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
+ private static final int MAGIC = 0x50535453;
+
+ // Where the "type"/"state" part of the data appears in an offset integer.
+ static int OFFSET_TYPE_SHIFT = 0;
+ static int OFFSET_TYPE_MASK = 0xff;
+ // Where the "which array" part of the data appears in an offset integer.
+ static int OFFSET_ARRAY_SHIFT = 8;
+ static int OFFSET_ARRAY_MASK = 0xff;
+ // Where the "index into array" part of the data appears in an offset integer.
+ static int OFFSET_INDEX_SHIFT = 16;
+ static int OFFSET_INDEX_MASK = 0xffff;
+
+ public String mReadError;
+ public String mTimePeriodStartClockStr;
+ public int mFlags;
+
+ public final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>();
+ public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
+
+ 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;
+ String mRuntime;
+ String mWebView;
+ boolean mRunning;
+
+ static final int LONGS_SIZE = 4096;
+ final ArrayList<long[]> mLongs = new ArrayList<long[]>();
+ int mNextLong;
+
+ int[] mAddLongTable;
+ int mAddLongTableSize;
+
+ public ProcessStats(boolean running) {
+ mRunning = running;
+ reset();
+ }
+
+ static private void printScreenLabel(PrintWriter pw, int offset) {
+ switch (offset) {
+ case ADJ_NOTHING:
+ pw.print(" ");
+ break;
+ case ADJ_SCREEN_OFF:
+ pw.print("Screen Off / ");
+ break;
+ case ADJ_SCREEN_ON:
+ pw.print("Screen On / ");
+ break;
+ default:
+ pw.print("?????????? / ");
+ break;
+ }
+ }
+
+ static public 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:
+ pw.print(" ");
+ break;
+ case ADJ_MEM_FACTOR_NORMAL:
+ pw.print("Norm / ");
+ break;
+ case ADJ_MEM_FACTOR_MODERATE:
+ pw.print("Mod / ");
+ break;
+ case ADJ_MEM_FACTOR_LOW:
+ pw.print("Low / ");
+ break;
+ case ADJ_MEM_FACTOR_CRITICAL:
+ pw.print("Crit / ");
+ break;
+ default:
+ pw.print("???? / ");
+ break;
+ }
+ }
+
+ static public 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 long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
+ int curState, long curStartTime, 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++) {
+ int state = imem+iscreen;
+ long time = durations[state];
+ String running = "";
+ if (curState == state) {
+ time += now - curStartTime;
+ if (pw != null) {
+ running = " (running)";
+ }
+ }
+ if (time != 0) {
+ if (pw != null) {
+ pw.print(prefix);
+ printScreenLabel(pw, printedScreen != iscreen
+ ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+ printedMem = imem;
+ TimeUtils.formatDuration(time, pw); pw.println(running);
+ }
+ totalTime += time;
+ }
+ }
+ }
+ if (totalTime != 0 && pw != null) {
+ pw.print(prefix);
+ printScreenLabel(pw, STATE_NOTHING);
+ pw.print("TOTAL: ");
+ TimeUtils.formatDuration(totalTime, pw);
+ pw.println();
+ }
+ return totalTime;
+ }
+
+ static void dumpAdjTimesCheckin(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;
+ }
+ if (time != 0) {
+ printAdjTagAndValue(pw, state, time);
+ }
+ }
+ }
+ }
+
+ static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName,
+ int uid, String serviceName, ServiceState svc, int serviceType, int opCount,
+ 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(",");
+ pw.print(opCount);
+ boolean didCurState = false;
+ for (int i=0; i<svc.mDurationsTableSize; i++) {
+ int off = svc.mDurationsTable[i];
+ int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ int memFactor = type / ServiceState.SERVICE_COUNT;
+ type %= ServiceState.SERVICE_COUNT;
+ if (type != serviceType) {
+ continue;
+ }
+ long time = svc.mProcessStats.getLong(off, 0);
+ if (curState == memFactor) {
+ didCurState = true;
+ time += now - curStartTime;
+ }
+ printAdjTagAndValue(pw, memFactor, time);
+ }
+ if (!didCurState && curState != STATE_NOTHING) {
+ printAdjTagAndValue(pw, curState, now - curStartTime);
+ }
+ pw.println();
+ }
+
+ static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
+ data.totalTime = 0;
+ data.numPss = data.minPss = data.avgPss = data.maxPss =
+ data.minUss = data.avgUss = data.maxUss = 0;
+ for (int is=0; is<data.screenStates.length; is++) {
+ for (int im=0; im<data.memStates.length; im++) {
+ for (int ip=0; ip<data.procStates.length; ip++) {
+ int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
+ + data.procStates[ip];
+ data.totalTime += proc.getDuration(bucket, now);
+ long samples = proc.getPssSampleCount(bucket);
+ if (samples > 0) {
+ long minPss = proc.getPssMinimum(bucket);
+ long avgPss = proc.getPssAverage(bucket);
+ long maxPss = proc.getPssMaximum(bucket);
+ long minUss = proc.getPssUssMinimum(bucket);
+ long avgUss = proc.getPssUssAverage(bucket);
+ long maxUss = proc.getPssUssMaximum(bucket);
+ if (data.numPss == 0) {
+ data.minPss = minPss;
+ data.avgPss = avgPss;
+ data.maxPss = maxPss;
+ data.minUss = minUss;
+ data.avgUss = avgUss;
+ data.maxUss = maxUss;
+ } else {
+ if (minPss < data.minPss) {
+ data.minPss = minPss;
+ }
+ data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
+ + (avgPss*(double)samples)) / (data.numPss+samples) );
+ if (maxPss > data.maxPss) {
+ data.maxPss = maxPss;
+ }
+ if (minUss < data.minUss) {
+ data.minUss = minUss;
+ }
+ data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
+ + (avgUss*(double)samples)) / (data.numPss+samples) );
+ if (maxUss > data.maxUss) {
+ data.maxUss = maxUss;
+ }
+ }
+ data.numPss += samples;
+ }
+ }
+ }
+ }
+ }
+
+ static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
+ int[] procStates, long now) {
+ long totalTime = 0;
+ /*
+ for (int i=0; i<proc.mDurationsTableSize; i++) {
+ int val = proc.mDurationsTable[i];
+ totalTime += proc.mState.getLong(val, 0);
+ if ((val&0xff) == proc.mCurState) {
+ totalTime += now - proc.mStartTime;
+ }
+ }
+ */
+ for (int is=0; is<screenStates.length; is++) {
+ for (int im=0; im<memStates.length; im++) {
+ for (int ip=0; ip<procStates.length; ip++) {
+ int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
+ + procStates[ip];
+ totalTime += proc.getDuration(bucket, now);
+ }
+ }
+ }
+ proc.mTmpTotalTime = totalTime;
+ return totalTime;
+ }
+
+ static 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<screenStates.length; is++) {
+ int printedMem = -1;
+ for (int im=0; im<memStates.length; im++) {
+ for (int ip=0; ip<procStates.length; ip++) {
+ final int iscreen = screenStates[is];
+ final int imem = memStates[im];
+ final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+ long time = proc.getDuration(bucket, now);
+ String running = "";
+ if (proc.mCurState == bucket) {
+ running = " (running)";
+ }
+ if (time != 0) {
+ pw.print(prefix);
+ if (screenStates.length > 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();
+ }
+ }
+
+ static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
+ int[] memStates, int[] procStates) {
+ boolean printedHeader = false;
+ int printedScreen = -1;
+ for (int is=0; is<screenStates.length; is++) {
+ int printedMem = -1;
+ for (int im=0; im<memStates.length; im++) {
+ for (int ip=0; ip<procStates.length; ip++) {
+ final int iscreen = screenStates[is];
+ final int imem = memStates[im];
+ final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
+ long count = proc.getPssSampleCount(bucket);
+ if (count > 0) {
+ if (!printedHeader) {
+ pw.print(prefix);
+ pw.print("PSS/USS (");
+ pw.print(proc.mPssTableSize);
+ pw.println(" entries):");
+ printedHeader = true;
+ }
+ pw.print(prefix);
+ pw.print(" ");
+ if (screenStates.length > 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(": ");
+ pw.print(count);
+ pw.print(" samples ");
+ printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+ pw.print(" / ");
+ printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
+ pw.println();
+ }
+ }
+ }
+ }
+ if (proc.mNumExcessiveWake != 0) {
+ pw.print(prefix); pw.print("Killed for excessive wake locks: ");
+ pw.print(proc.mNumExcessiveWake); pw.println(" times");
+ }
+ if (proc.mNumExcessiveCpu != 0) {
+ pw.print(prefix); pw.print("Killed for excessive CPU use: ");
+ pw.print(proc.mNumExcessiveCpu); pw.println(" times");
+ }
+ }
+
+ static 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]]);
+ }
+ }
+ }
+ }
+ }
+
+ static 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.getDuration(bucket, now);
+ }
+ }
+ }
+ pw.print(CSV_SEP);
+ pw.print(totalTime);
+ }
+ }
+ }
+ }
+
+ static 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.mName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, proc.mUid);
+ pw.print(" (");
+ pw.print(proc.mDurationsTableSize);
+ pw.print(" entries)");
+ pw.println(":");
+ dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now);
+ if (proc.mPssTableSize > 0) {
+ dumpProcessPss(pw, innerPrefix, proc, screenStates, memStates, procStates);
+ }
+ }
+ }
+
+ static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
+ String label, int[] screenStates, int[] memStates, int[] procStates,
+ long now, long totalTime, boolean full) {
+ ProcessDataCollection totals = new ProcessDataCollection(screenStates,
+ memStates, procStates);
+ computeProcessData(proc, totals, now);
+ if (totals.totalTime != 0 || totals.numPss != 0) {
+ if (prefix != null) {
+ pw.print(prefix);
+ }
+ if (label != null) {
+ pw.print(label);
+ }
+ totals.print(pw, totalTime, full);
+ if (prefix != null) {
+ pw.println();
+ }
+ }
+ }
+
+ static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
+ ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
+ long now, long totalTime) {
+ for (int i=procs.size()-1; i>=0; i--) {
+ ProcessState proc = procs.get(i);
+ pw.print(prefix);
+ pw.print("* ");
+ pw.print(proc.mName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, proc.mUid);
+ pw.println(":");
+ dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates,
+ procStates, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates,
+ new int[] { STATE_PERSISTENT }, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates,
+ new int[] {STATE_TOP}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Imp Fg: ", screenStates, memStates,
+ new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Imp Bg: ", screenStates, memStates,
+ new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates,
+ new int[] {STATE_BACKUP}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Heavy Wgt: ", screenStates, memStates,
+ new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates,
+ new int[] {STATE_SERVICE}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Service Rs: ", screenStates, memStates,
+ new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Receiver: ", screenStates, memStates,
+ new int[] {STATE_RECEIVER}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Home: ", screenStates, memStates,
+ new int[] {STATE_HOME}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " (Last Act): ", screenStates, memStates,
+ new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates,
+ new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
+ STATE_CACHED_EMPTY}, now, totalTime, true);
+ }
+ }
+
+ static void printPercent(PrintWriter pw, double fraction) {
+ fraction *= 100;
+ if (fraction < 1) {
+ pw.print(String.format("%.2f", fraction));
+ } else if (fraction < 10) {
+ pw.print(String.format("%.1f", fraction));
+ } else {
+ pw.print(String.format("%.0f", fraction));
+ }
+ pw.print("%");
+ }
+
+ static void printSizeValue(PrintWriter pw, long number) {
+ float result = number;
+ String suffix = "";
+ if (result > 900) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ value = String.format("%.1f", result);
+ } else if (result < 100) {
+ value = String.format("%.0f", result);
+ } else {
+ value = String.format("%.0f", result);
+ }
+ pw.print(value);
+ pw.print(suffix);
+ }
+
+ public static 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();
+ }
+ }
+
+ static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
+ int index = value/mod;
+ if (index >= 0 && index < array.length) {
+ pw.print(array[index]);
+ } else {
+ pw.print('?');
+ }
+ return value - index*mod;
+ }
+
+ static void printProcStateTag(PrintWriter pw, int state) {
+ state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD*STATE_COUNT);
+ state = printArrayEntry(pw, ADJ_MEM_TAGS, state, STATE_COUNT);
+ printArrayEntry(pw, STATE_TAGS, state, 1);
+ }
+
+ static void printAdjTag(PrintWriter pw, int state) {
+ state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD);
+ printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
+ }
+
+ static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
+ pw.print(',');
+ printProcStateTag(pw, state);
+ pw.print(':');
+ pw.print(value);
+ }
+
+ static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
+ pw.print(',');
+ printAdjTag(pw, state);
+ pw.print(':');
+ pw.print(value);
+ }
+
+ static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
+ boolean didCurState = false;
+ for (int i=0; i<proc.mDurationsTableSize; i++) {
+ int off = proc.mDurationsTable[i];
+ int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ long time = proc.mProcessStats.getLong(off, 0);
+ if (proc.mCurState == type) {
+ didCurState = true;
+ time += now - proc.mStartTime;
+ }
+ printProcStateTagAndValue(pw, type, time);
+ }
+ if (!didCurState && proc.mCurState != STATE_NOTHING) {
+ printProcStateTagAndValue(pw, proc.mCurState, now - proc.mStartTime);
+ }
+ }
+
+ static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
+ for (int i=0; i<proc.mPssTableSize; i++) {
+ int off = proc.mPssTable[i];
+ int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ long count = proc.mProcessStats.getLong(off, PSS_SAMPLE_COUNT);
+ long min = proc.mProcessStats.getLong(off, PSS_MINIMUM);
+ long avg = proc.mProcessStats.getLong(off, PSS_AVERAGE);
+ long max = proc.mProcessStats.getLong(off, PSS_MAXIMUM);
+ long umin = proc.mProcessStats.getLong(off, PSS_USS_MINIMUM);
+ long uavg = proc.mProcessStats.getLong(off, PSS_USS_AVERAGE);
+ long umax = proc.mProcessStats.getLong(off, PSS_USS_MAXIMUM);
+ pw.print(',');
+ printProcStateTag(pw, type);
+ pw.print(':');
+ pw.print(count);
+ pw.print(':');
+ pw.print(min);
+ pw.print(':');
+ pw.print(avg);
+ pw.print(':');
+ pw.print(max);
+ pw.print(':');
+ pw.print(umin);
+ pw.print(':');
+ pw.print(uavg);
+ pw.print(':');
+ pw.print(umax);
+ }
+ }
+
+ 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();
+ long now = SystemClock.uptimeMillis();
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ for (int ip=procMap.size()-1; ip>=0; ip--) {
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=uids.size()-1; iu>=0; iu--) {
+ uids.valueAt(iu).resetSafely(now);
+ }
+ }
+ ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+ for (int ip=pkgMap.size()-1; ip>=0; ip--) {
+ SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+ for (int iu=uids.size()-1; iu>=0; iu--) {
+ PackageState pkgState = uids.valueAt(iu);
+ for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
+ pkgState.mProcesses.valueAt(iproc).resetSafely(now);
+ }
+ for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
+ ServiceState ss = pkgState.mServices.valueAt(isvc);
+ if (ss.isActive()) {
+ pkgState.mServices.valueAt(isvc).resetSafely(now);
+ } else {
+ pkgState.mServices.removeAt(isvc);
+ }
+ }
+ }
+ }
+ mStartTime = SystemClock.uptimeMillis();
+ if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
+ }
+
+ private void resetCommon() {
+ mTimePeriodStartClock = System.currentTimeMillis();
+ buildTimePeriodStartClockStr();
+ mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+ mLongs.clear();
+ mLongs.add(new long[LONGS_SIZE]);
+ mNextLong = 0;
+ Arrays.fill(mMemFactorDurations, 0);
+ mStartTime = 0;
+ mReadError = null;
+ mFlags = 0;
+ evaluateSystemProperties(true);
+ }
+
+ public boolean evaluateSystemProperties(boolean update) {
+ boolean changed = false;
+ String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib",
+ VMRuntime.getRuntime().vmLibrary());
+ if (!Objects.equals(runtime, mRuntime)) {
+ changed = true;
+ if (update) {
+ mRuntime = runtime;
+ }
+ }
+ String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
+ if (!Objects.equals(webview, mWebView)) {
+ changed = true;
+ if (update) {
+ mWebView = webview;
+ }
+ }
+ return changed;
+ }
+
+ private void buildTimePeriodStartClockStr() {
+ mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ mTimePeriodStartClock).toString();
+ }
+
+ static final int[] BAD_TABLE = new int[0];
+
+ private int[] readTableFromParcel(Parcel in, String name, String what) {
+ final int size = in.readInt();
+ if (size < 0) {
+ Slog.w(TAG, "Ignoring existing stats; bad " + what + " table size: " + size);
+ return BAD_TABLE;
+ }
+ if (size == 0) {
+ return null;
+ }
+ final int[] table = new int[size];
+ for (int i=0; i<size; i++) {
+ table[i] = in.readInt();
+ if (DEBUG) Slog.i(TAG, "Reading in " + name + " table #" + i + ": "
+ + ProcessStats.printLongOffset(table[i]));
+ if (!validateLongOffset(table[i])) {
+ Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: "
+ + ProcessStats.printLongOffset(table[i]));
+ return null;
+ }
+ }
+ return table;
+ }
+
+ public void writeToParcel(Parcel out) {
+ long now = SystemClock.uptimeMillis();
+ out.writeInt(MAGIC);
+ out.writeInt(PARCEL_VERSION);
+ out.writeInt(STATE_COUNT);
+ out.writeInt(ADJ_COUNT);
+ out.writeInt(PSS_COUNT);
+ out.writeInt(LONGS_SIZE);
+
+ out.writeLong(mTimePeriodStartClock);
+ out.writeLong(mTimePeriodStartRealtime);
+ out.writeLong(mTimePeriodEndRealtime);
+ out.writeString(mRuntime);
+ out.writeString(mWebView);
+ out.writeInt(mFlags);
+
+ out.writeInt(mLongs.size());
+ out.writeInt(mNextLong);
+ for (int i=0; i<(mLongs.size()-1); i++) {
+ out.writeLongArray(mLongs.get(i));
+ }
+ long[] lastLongs = mLongs.get(mLongs.size()-1);
+ for (int i=0; i<mNextLong; i++) {
+ out.writeLong(lastLongs[i]);
+ if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]);
+ }
+
+ if (mMemFactor != STATE_NOTHING) {
+ mMemFactorDurations[mMemFactor] += now - mStartTime;
+ mStartTime = now;
+ }
+ out.writeLongArray(mMemFactorDurations);
+
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ final int NPROC = procMap.size();
+ out.writeInt(NPROC);
+ for (int ip=0; ip<NPROC; ip++) {
+ out.writeString(procMap.keyAt(ip));
+ 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));
+ ProcessState proc = uids.valueAt(iu);
+ out.writeString(proc.mPackage);
+ proc.writeToParcel(out, now);
+ }
+ }
+ ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+ final int NPKG = pkgMap.size();
+ out.writeInt(NPKG);
+ for (int ip=0; ip<NPKG; ip++) {
+ out.writeString(pkgMap.keyAt(ip));
+ SparseArray<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));
+ PackageState pkgState = uids.valueAt(iu);
+ final int NPROCS = pkgState.mProcesses.size();
+ out.writeInt(NPROCS);
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ out.writeString(pkgState.mProcesses.keyAt(iproc));
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (proc.mCommonProcess == 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));
+ ServiceState svc = pkgState.mServices.valueAt(isvc);
+ svc.writeToParcel(out, now);
+ }
+ }
+ }
+ }
+
+ private boolean readCheckedInt(Parcel in, int val, String what) {
+ int got;
+ if ((got=in.readInt()) != val) {
+ mReadError = "bad " + what + ": " + got;
+ return false;
+ }
+ return true;
+ }
+
+ 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 && version != 6) {
+ 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, LONGS_SIZE, "longs size")) {
+ return;
+ }
+
+ mTimePeriodStartClock = in.readLong();
+ buildTimePeriodStartClockStr();
+ mTimePeriodStartRealtime = in.readLong();
+ mTimePeriodEndRealtime = in.readLong();
+ if (version == PARCEL_VERSION) {
+ mRuntime = in.readString();
+ mWebView = in.readString();
+ }
+ mFlags = in.readInt();
+
+ final int NLONGS = in.readInt();
+ final int NEXTLONG = in.readInt();
+ mLongs.clear();
+ for (int i=0; i<(NLONGS-1); i++) {
+ while (i >= mLongs.size()) {
+ mLongs.add(new long[LONGS_SIZE]);
+ }
+ in.readLongArray(mLongs.get(i));
+ }
+ long[] longs = new long[LONGS_SIZE];
+ mNextLong = NEXTLONG;
+ for (int i=0; i<NEXTLONG; i++) {
+ longs[i] = in.readLong();
+ if (DEBUG) Slog.d(TAG, "Reading last long #" + i + ": " + longs[i]);
+ }
+ mLongs.add(longs);
+
+ in.readLongArray(mMemFactorDurations);
+
+ int NPROC = in.readInt();
+ if (NPROC < 0) {
+ mReadError = "bad process count: " + NPROC;
+ return;
+ }
+ while (NPROC > 0) {
+ NPROC--;
+ String procName = in.readString();
+ 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--;
+ int uid = in.readInt();
+ if (uid < 0) {
+ mReadError = "bad uid: " + uid;
+ return;
+ }
+ String pkgName = in.readString();
+ if (pkgName == null) {
+ mReadError = "bad process package name";
+ return;
+ }
+ ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
+ if (proc != null) {
+ if (!proc.readFromParcel(in, false)) {
+ return;
+ }
+ } else {
+ proc = new ProcessState(this, pkgName, uid, procName);
+ if (!proc.readFromParcel(in, true)) {
+ return;
+ }
+ }
+ if (DEBUG) Slog.d(TAG, "Adding process: " + procName + " " + uid + " " + proc);
+ mProcesses.put(procName, uid, proc);
+ }
+ }
+
+ if (DEBUG) 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--;
+ String pkgName = in.readString();
+ 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--;
+ int uid = in.readInt();
+ if (uid < 0) {
+ mReadError = "bad uid: " + uid;
+ return;
+ }
+ PackageState pkgState = new PackageState(uid);
+ mPackages.put(pkgName, uid, pkgState);
+ int NPROCS = in.readInt();
+ if (NPROCS < 0) {
+ mReadError = "bad package process count: " + NPROCS;
+ return;
+ }
+ while (NPROCS > 0) {
+ NPROCS--;
+ String procName = in.readString();
+ if (procName == null) {
+ mReadError = "bad package process name";
+ return;
+ }
+ int hasProc = in.readInt();
+ if (DEBUG) Slog.d(TAG, "Reading package " + pkgName + " " + uid
+ + " process " + procName + " hasProc=" + hasProc);
+ ProcessState commonProc = mProcesses.get(procName, uid);
+ if (DEBUG) 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, procName, 0);
+ if (!proc.readFromParcel(in, true)) {
+ return;
+ }
+ }
+ if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " process: "
+ + procName + " " + uid + " " + proc);
+ pkgState.mProcesses.put(procName, proc);
+ } else {
+ if (DEBUG) 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;
+ }
+ ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
+ if (serv == null) {
+ serv = new ServiceState(this, pkgName, null);
+ }
+ if (!serv.readFromParcel(in)) {
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " service: "
+ + serviceName + " " + uid + " " + serv);
+ pkgState.mServices.put(serviceName, serv);
+ }
+ }
+ }
+
+ if (DEBUG) Slog.d(TAG, "Successfully read procstats!");
+ }
+
+ int addLongData(int index, int type, int num) {
+ int tableLen = mAddLongTable != null ? mAddLongTable.length : 0;
+ if (mAddLongTableSize >= tableLen) {
+ int newSize = ArrayUtils.idealIntArraySize(tableLen + 1);
+ int[] newTable = new int[newSize];
+ if (tableLen > 0) {
+ System.arraycopy(mAddLongTable, 0, newTable, 0, tableLen);
+ }
+ mAddLongTable = newTable;
+ }
+ if (mAddLongTableSize > 0 && mAddLongTableSize - index != 0) {
+ System.arraycopy(mAddLongTable, index, mAddLongTable, index + 1,
+ mAddLongTableSize - index);
+ }
+ int off = allocLongData(num);
+ mAddLongTable[index] = type | off;
+ mAddLongTableSize++;
+ return off;
+ }
+
+ int allocLongData(int num) {
+ int whichLongs = mLongs.size()-1;
+ long[] longs = mLongs.get(whichLongs);
+ if (mNextLong + num > longs.length) {
+ longs = new long[LONGS_SIZE];
+ mLongs.add(longs);
+ whichLongs++;
+ mNextLong = 0;
+ }
+ int off = (whichLongs<<OFFSET_ARRAY_SHIFT) | (mNextLong<<OFFSET_INDEX_SHIFT);
+ mNextLong += num;
+ return off;
+ }
+
+ boolean validateLongOffset(int off) {
+ int arr = (off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK;
+ if (arr >= mLongs.size()) {
+ return false;
+ }
+ int idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
+ if (idx >= LONGS_SIZE) {
+ return false;
+ }
+ if (DEBUG) Slog.d(TAG, "Validated long " + printLongOffset(off)
+ + ": " + getLong(off, 0));
+ return true;
+ }
+
+ static String printLongOffset(int off) {
+ StringBuilder sb = new StringBuilder(16);
+ sb.append("a"); sb.append((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ sb.append("i"); sb.append((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK);
+ sb.append("t"); sb.append((off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK);
+ return sb.toString();
+ }
+
+ void setLong(int off, int index, long value) {
+ long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)] = value;
+ }
+
+ long getLong(int off, int index) {
+ long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ return longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)];
+ }
+
+ static int binarySearch(int[] array, int size, int value) {
+ int lo = 0;
+ int hi = size - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ int midVal = (array[mid] >> OFFSET_TYPE_SHIFT) & OFFSET_TYPE_MASK;
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else {
+ return mid; // value found
+ }
+ }
+ return ~lo; // value not present
+ }
+
+ public 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 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.mName, 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;
+ }
+
+ public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) {
+ long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+ mStartTime, now);
+ ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+ boolean printedHeader = false;
+ 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 pkgState = uids.valueAt(iu);
+ final int NPROCS = pkgState.mProcesses.size();
+ final int NSRVS = pkgState.mServices.size();
+ 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 (dumpAll) {
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ pw.print(" Process ");
+ pw.print(pkgState.mProcesses.keyAt(iproc));
+ pw.print(" (");
+ pw.print(proc.mDurationsTableSize);
+ pw.print(" entries)");
+ pw.println(":");
+ dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES);
+ if (dumpAll) {
+ pw.print(" mNumStartedServices=");
+ pw.println(proc.mNumStartedServices);
+ }
+ }
+ } else {
+ ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ procs.add(pkgState.mProcesses.valueAt(iproc));
+ }
+ dumpProcessSummaryLocked(pw, " ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ NON_CACHED_PROC_STATES, now, totalTime);
+ }
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ if (dumpAll) {
+ pw.print(" Service ");
+ } else {
+ pw.print(" * ");
+ }
+ pw.print(pkgState.mServices.keyAt(isvc));
+ pw.println(":");
+ ServiceState svc = pkgState.mServices.valueAt(isvc);
+ dumpServiceStats(pw, " ", " ", " ", "Started", svc,
+ svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
+ svc.mStartedStartTime, now, totalTime, dumpAll);
+ dumpServiceStats(pw, " ", " ", " ", "Bound", svc,
+ svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
+ svc.mBoundStartTime, now, totalTime, dumpAll);
+ dumpServiceStats(pw, " ", " ", " ", "Executing", svc,
+ svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
+ svc.mExecStartTime, now, totalTime, dumpAll);
+ }
+ }
+ }
+
+ if (reqPackage == null) {
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ printedHeader = false;
+ 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 proc = uids.valueAt(iu);
+ if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
+ && proc.mPssTableSize == 0) {
+ continue;
+ }
+ if (!printedHeader) {
+ pw.println("Process Stats:");
+ printedHeader = true;
+ }
+ pw.print(" * "); pw.print(procName); pw.print(" / ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(" ("); pw.print(proc.mDurationsTableSize);
+ pw.print(" entries)"); pw.println(":");
+ dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES);
+ }
+ }
+
+ pw.println();
+ pw.println("Summary:");
+ dumpSummaryLocked(pw, reqPackage, now);
+ } else {
+ pw.println();
+ 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);
+ }
+ }
+
+ static long dumpSingleServiceTime(PrintWriter pw, String prefix, ServiceState service,
+ int serviceType, int curState, long curStartTime, 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++) {
+ int state = imem+iscreen;
+ long time = service.getDuration(serviceType, curState, curStartTime,
+ state, now);
+ String running = "";
+ if (curState == state) {
+ time += now - curStartTime;
+ if (pw != null) {
+ running = " (running)";
+ }
+ }
+ if (time != 0) {
+ if (pw != null) {
+ pw.print(prefix);
+ printScreenLabel(pw, printedScreen != iscreen
+ ? iscreen : STATE_NOTHING);
+ printedScreen = iscreen;
+ printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
+ printedMem = imem;
+ TimeUtils.formatDuration(time, pw); pw.println(running);
+ }
+ totalTime += time;
+ }
+ }
+ }
+ if (totalTime != 0 && pw != null) {
+ pw.print(prefix);
+ printScreenLabel(pw, STATE_NOTHING);
+ pw.print("TOTAL: ");
+ TimeUtils.formatDuration(totalTime, pw);
+ pw.println();
+ }
+ return totalTime;
+ }
+
+ void dumpServiceStats(PrintWriter pw, String prefix, String prefixInner,
+ String headerPrefix, String header, ServiceState service,
+ int count, int serviceType, int state, long startTime, long now, long totalTime,
+ boolean dumpAll) {
+ if (count != 0) {
+ if (dumpAll) {
+ pw.print(prefix); pw.print(header);
+ pw.print(" op count "); pw.print(count); pw.println(":");
+ dumpSingleServiceTime(pw, prefixInner, service, serviceType, state, startTime,
+ now);
+ } else {
+ long myTime = dumpSingleServiceTime(null, null, service, serviceType, state,
+ startTime, now);
+ pw.print(prefix); pw.print(headerPrefix); pw.print(header);
+ pw.print(" count "); pw.print(count);
+ pw.print(" / time ");
+ printPercent(pw, (double)myTime/(double)totalTime);
+ pw.println();
+ }
+ }
+ }
+
+ public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
+ long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
+ mStartTime, now);
+ dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
+ pw.println();
+ dumpTotalsLocked(pw, now);
+ }
+
+ void dumpTotalsLocked(PrintWriter pw, long now) {
+ pw.println("Run time Stats:");
+ dumpSingleTime(pw, " ", mMemFactorDurations, mMemFactor, mStartTime, now);
+ pw.println();
+ pw.print(" Start time: ");
+ pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
+ 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)");
+ }
+ pw.print(' ');
+ pw.print(mRuntime);
+ pw.print(' ');
+ pw.print(mWebView);
+ pw.println();
+ }
+
+ void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
+ int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime,
+ String reqPackage) {
+ ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
+ procStates, now, reqPackage);
+ if (procs.size() > 0) {
+ if (header != null) {
+ pw.println();
+ pw.println(header);
+ }
+ dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates, procStates,
+ now, totalTime);
+ }
+ }
+
+ public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
+ int[] procStates, long now, String reqPackage) {
+ ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+ ArrayMap<String, SparseArray<PackageState>> pkgMap = 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++) {
+ ProcessState proc = state.mProcesses.valueAt(iproc);
+ foundProcs.add(proc.mCommonProcess);
+ }
+ }
+ }
+ 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) {
+ if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
+ return -1;
+ } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+ return outProcs;
+ }
+
+ String collapseString(String pkgName, String itemName) {
+ if (itemName.startsWith(pkgName)) {
+ final int ITEMLEN = itemName.length();
+ final int PKGLEN = pkgName.length();
+ if (ITEMLEN == PKGLEN) {
+ return "";
+ } else if (ITEMLEN >= PKGLEN) {
+ if (itemName.charAt(PKGLEN) == '.') {
+ return itemName.substring(PKGLEN);
+ }
+ }
+ }
+ return itemName;
+ }
+
+ public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
+ final long now = SystemClock.uptimeMillis();
+ ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+ pw.println("vers,3");
+ 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");
+ }
+ pw.println();
+ pw.print("config,"); pw.print(mRuntime); pw.print(','); pw.println(mWebView);
+ 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 pkgState = uids.valueAt(iu);
+ final int NPROCS = pkgState.mProcesses.size();
+ final int NSRVS = pkgState.mServices.size();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ pw.print("pkgproc,");
+ pw.print(pkgName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
+ dumpAllProcessStateCheckin(pw, proc, now);
+ pw.println();
+ if (proc.mPssTableSize > 0) {
+ pw.print("pkgpss,");
+ pw.print(pkgName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
+ dumpAllProcessPssCheckin(pw, proc);
+ pw.println();
+ }
+ if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0) {
+ pw.print("pkgkills,");
+ pw.print(pkgName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
+ pw.print(",");
+ pw.print(proc.mNumExcessiveWake);
+ pw.print(",");
+ pw.print(proc.mNumExcessiveCpu);
+ pw.println();
+ }
+ }
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ String serviceName = collapseString(pkgName,
+ pkgState.mServices.keyAt(isvc));
+ ServiceState svc = pkgState.mServices.valueAt(isvc);
+ dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, serviceName,
+ svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
+ svc.mStartedState, svc.mStartedStartTime, now);
+ dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, serviceName,
+ svc, ServiceState.SERVICE_BOUND, svc.mBoundCount,
+ svc.mBoundState, svc.mBoundStartTime, now);
+ dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, serviceName,
+ svc, ServiceState.SERVICE_EXEC, svc.mExecCount,
+ svc.mExecState, svc.mExecStartTime, now);
+ }
+ }
+ }
+
+ 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++) {
+ int uid = uids.keyAt(iu);
+ ProcessState procState = uids.valueAt(iu);
+ if (procState.mDurationsTableSize > 0) {
+ pw.print("proc,");
+ pw.print(procName);
+ pw.print(",");
+ pw.print(uid);
+ dumpAllProcessStateCheckin(pw, procState, now);
+ pw.println();
+ }
+ if (procState.mPssTableSize > 0) {
+ pw.print("pss,");
+ pw.print(procName);
+ pw.print(",");
+ pw.print(uid);
+ dumpAllProcessPssCheckin(pw, procState);
+ pw.println();
+ }
+ if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0) {
+ pw.print("kills,");
+ pw.print(procName);
+ pw.print(",");
+ pw.print(uid);
+ pw.print(",");
+ pw.print(procState.mNumExcessiveWake);
+ pw.print(",");
+ pw.print(procState.mNumExcessiveCpu);
+ pw.println();
+ }
+ }
+ }
+ pw.print("total");
+ dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
+ mStartTime, now);
+ pw.println();
+ }
+
+ public static final class ProcessState {
+ final ProcessStats mProcessStats;
+ final ProcessState mCommonProcess;
+ final String mPackage;
+ final int mUid;
+ final String mName;
+
+ int[] mDurationsTable;
+ int mDurationsTableSize;
+
+ //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
+ int mCurState = STATE_NOTHING;
+ long mStartTime;
+
+ int mLastPssState = STATE_NOTHING;
+ long mLastPssTime;
+ int[] mPssTable;
+ int mPssTableSize;
+
+ int mNumStartedServices;
+
+ int mNumExcessiveWake;
+ int mNumExcessiveCpu;
+
+ boolean mMultiPackage;
+
+ long mTmpTotalTime;
+
+ /**
+ * 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(ProcessStats processStats, String pkg, int uid, String name) {
+ mProcessStats = processStats;
+ mCommonProcess = this;
+ 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) {
+ mProcessStats = commonProcess.mProcessStats;
+ 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);
+ if (mDurationsTable != null) {
+ mProcessStats.mAddLongTable = new int[mDurationsTable.length];
+ mProcessStats.mAddLongTableSize = 0;
+ for (int i=0; i<mDurationsTableSize; i++) {
+ int origEnt = mDurationsTable[i];
+ int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ int newOff = mProcessStats.addLongData(i, type, 1);
+ mProcessStats.mAddLongTable[i] = newOff | type;
+ mProcessStats.setLong(newOff, 0, mProcessStats.getLong(origEnt, 0));
+ }
+ pnew.mDurationsTable = mProcessStats.mAddLongTable;
+ pnew.mDurationsTableSize = mProcessStats.mAddLongTableSize;
+ }
+ if (mPssTable != null) {
+ mProcessStats.mAddLongTable = new int[mPssTable.length];
+ mProcessStats.mAddLongTableSize = 0;
+ for (int i=0; i<mPssTableSize; i++) {
+ int origEnt = mPssTable[i];
+ int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
+ int newOff = mProcessStats.addLongData(i, type, PSS_COUNT);
+ mProcessStats.mAddLongTable[i] = newOff | type;
+ for (int j=0; j<PSS_COUNT; j++) {
+ mProcessStats.setLong(newOff, j, mProcessStats.getLong(origEnt, j));
+ }
+ }
+ pnew.mPssTable = mProcessStats.mAddLongTable;
+ pnew.mPssTableSize = mProcessStats.mAddLongTableSize;
+ }
+ pnew.mNumExcessiveWake = mNumExcessiveWake;
+ pnew.mNumExcessiveCpu = mNumExcessiveCpu;
+ pnew.mNumStartedServices = mNumStartedServices;
+ return pnew;
+ }
+
+ void resetSafely(long now) {
+ mDurationsTable = null;
+ mDurationsTableSize = 0;
+ mStartTime = now;
+ mLastPssState = STATE_NOTHING;
+ mLastPssTime = 0;
+ mPssTable = null;
+ mPssTableSize = 0;
+ mNumExcessiveWake = 0;
+ mNumExcessiveCpu = 0;
+ }
+
+ void writeToParcel(Parcel out, long now) {
+ commitStateTime(now);
+ out.writeInt(mMultiPackage ? 1 : 0);
+ out.writeInt(mDurationsTableSize);
+ for (int i=0; i<mDurationsTableSize; i++) {
+ if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
+ + printLongOffset(mDurationsTable[i]));
+ out.writeInt(mDurationsTable[i]);
+ }
+ out.writeInt(mPssTableSize);
+ for (int i=0; i<mPssTableSize; i++) {
+ if (DEBUG) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
+ + printLongOffset(mPssTable[i]));
+ out.writeInt(mPssTable[i]);
+ }
+ out.writeInt(mNumExcessiveWake);
+ out.writeInt(mNumExcessiveCpu);
+ }
+
+ boolean readFromParcel(Parcel in, boolean fully) {
+ boolean multiPackage = in.readInt() != 0;
+ if (fully) {
+ mMultiPackage = multiPackage;
+ }
+ if (DEBUG) Slog.d(TAG, "Reading durations table...");
+ mDurationsTable = mProcessStats.readTableFromParcel(in, mName, "durations");
+ if (mDurationsTable == BAD_TABLE) {
+ return false;
+ }
+ mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
+ if (DEBUG) Slog.d(TAG, "Reading pss table...");
+ mPssTable = mProcessStats.readTableFromParcel(in, mName, "pss");
+ if (mPssTable == BAD_TABLE) {
+ return false;
+ }
+ mPssTableSize = mPssTable != null ? mPssTable.length : 0;
+ mNumExcessiveWake = in.readInt();
+ mNumExcessiveCpu = in.readInt();
+ return true;
+ }
+
+ /**
+ * Update the current state of the given list of processes.
+ *
+ * @param state Current ActivityManager.PROCESS_STATE_*
+ * @param memFactor Current mem factor constant.
+ * @param now Current time.
+ * @param pkgList Processes to update.
+ */
+ public void setState(int state, int memFactor, long now,
+ ArrayMap<String, ProcessState> pkgList) {
+ if (state < 0) {
+ state = mNumStartedServices > 0
+ ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
+ } else {
+ state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
+ }
+
+ // First update the common process.
+ mCommonProcess.setState(state, now);
+
+ // If the common process is not multi-package, there is nothing else to do.
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ if (pkgList != null) {
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).setState(state, now);
+ }
+ }
+ }
+
+ void setState(int state, long now) {
+ if (mCurState != state) {
+ //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
+ commitStateTime(now);
+ mCurState = state;
+ }
+ }
+
+ void commitStateTime(long now) {
+ if (mCurState != STATE_NOTHING) {
+ long dur = now - mStartTime;
+ if (dur > 0) {
+ int idx = binarySearch(mDurationsTable, mDurationsTableSize, mCurState);
+ int off;
+ if (idx >= 0) {
+ off = mDurationsTable[idx];
+ } else {
+ mProcessStats.mAddLongTable = mDurationsTable;
+ mProcessStats.mAddLongTableSize = mDurationsTableSize;
+ off = mProcessStats.addLongData(~idx, mCurState, 1);
+ mDurationsTable = mProcessStats.mAddLongTable;
+ mDurationsTableSize = mProcessStats.mAddLongTableSize;
+ }
+ long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
+ }
+ }
+ mStartTime = now;
+ }
+
+ void incStartedServices(int memFactor, long now) {
+ if (mCommonProcess != this) {
+ mCommonProcess.incStartedServices(memFactor, now);
+ }
+ mNumStartedServices++;
+ if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
+ setState(STATE_NOTHING, memFactor, now, null);
+ }
+ }
+
+ void decStartedServices(int memFactor, long now) {
+ if (mCommonProcess != this) {
+ mCommonProcess.decStartedServices(memFactor, now);
+ }
+ mNumStartedServices--;
+ if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
+ setState(STATE_NOTHING, memFactor, now, null);
+ } else if (mNumStartedServices < 0) {
+ throw new IllegalStateException("Proc started services underrun: pkg="
+ + mPackage + " uid=" + mUid + " name=" + mName);
+ }
+ }
+
+ public void addPss(long pss, long uss, boolean always) {
+ if (!always) {
+ if (mLastPssState == mCurState && SystemClock.uptimeMillis()
+ < (mLastPssTime+(30*1000))) {
+ return;
+ }
+ }
+ mLastPssState = mCurState;
+ mLastPssTime = SystemClock.uptimeMillis();
+ if (mCurState != STATE_NOTHING) {
+ int idx = binarySearch(mPssTable, mPssTableSize, mCurState);
+ int off;
+ if (idx >= 0) {
+ off = mPssTable[idx];
+ } else {
+ mProcessStats.mAddLongTable = mPssTable;
+ mProcessStats.mAddLongTableSize = mPssTableSize;
+ off = mProcessStats.addLongData(~idx, mCurState, PSS_COUNT);
+ mPssTable = mProcessStats.mAddLongTable;
+ mPssTableSize = mProcessStats.mAddLongTableSize;
+ }
+ long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
+ long count = longs[idx+PSS_SAMPLE_COUNT];
+ if (count == 0) {
+ longs[idx+PSS_SAMPLE_COUNT] = 1;
+ longs[idx+PSS_MINIMUM] = pss;
+ longs[idx+PSS_AVERAGE] = pss;
+ longs[idx+PSS_MAXIMUM] = pss;
+ longs[idx+PSS_USS_MINIMUM] = uss;
+ longs[idx+PSS_USS_AVERAGE] = uss;
+ longs[idx+PSS_USS_MAXIMUM] = uss;
+ } else {
+ longs[idx+PSS_SAMPLE_COUNT] = count+1;
+ if (longs[idx+PSS_MINIMUM] > pss) {
+ longs[idx+PSS_MINIMUM] = pss;
+ }
+ longs[idx+PSS_AVERAGE] = (long)(
+ ((longs[idx+PSS_AVERAGE]*(double)count)+pss) / (count+1) );
+ if (longs[idx+PSS_MAXIMUM] < pss) {
+ longs[idx+PSS_MAXIMUM] = pss;
+ }
+ if (longs[idx+PSS_USS_MINIMUM] > uss) {
+ longs[idx+PSS_USS_MINIMUM] = uss;
+ }
+ longs[idx+PSS_USS_AVERAGE] = (long)(
+ ((longs[idx+PSS_USS_AVERAGE]*(double)count)+uss) / (count+1) );
+ if (longs[idx+PSS_USS_MAXIMUM] < uss) {
+ longs[idx+PSS_USS_MAXIMUM] = uss;
+ }
+ }
+ }
+ }
+
+ public void reportExcessiveWake(ArrayMap<String, ProcessState> pkgList) {
+ mCommonProcess.mNumExcessiveWake++;
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).mNumExcessiveWake++;
+ }
+ }
+
+ public void reportExcessiveCpu(ArrayMap<String, ProcessState> pkgList) {
+ mCommonProcess.mNumExcessiveCpu++;
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
+ }
+ }
+
+ ProcessState pullFixedProc(String pkgName) {
+ if (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.
+ ProcessState proc = mProcessStats.mPackages.get(pkgName,
+ mUid).mProcesses.get(mName);
+ if (proc == null) {
+ throw new IllegalStateException("Didn't create per-package process");
+ }
+ return proc;
+ }
+ return this;
+ }
+
+ private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList,
+ int index) {
+ ProcessState proc = pkgList.valueAt(index);
+ 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 = mProcessStats.mPackages.get(pkgList.keyAt(index),
+ proc.mUid).mProcesses.get(proc.mName);
+ if (proc == null) {
+ throw new IllegalStateException("Didn't create per-package process");
+ }
+ pkgList.setValueAt(index, proc);
+ }
+ return proc;
+ }
+
+ long getDuration(int state, long now) {
+ int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+ long time = idx >= 0 ? mProcessStats.getLong(mDurationsTable[idx], 0) : 0;
+ if (mCurState == state) {
+ time += now - mStartTime;
+ }
+ return time;
+ }
+
+ long getPssSampleCount(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
+ }
+
+ long getPssMinimum(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
+ }
+
+ long getPssAverage(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
+ }
+
+ long getPssMaximum(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
+ }
+
+ long getPssUssMinimum(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
+ }
+
+ long getPssUssAverage(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
+ }
+
+ long getPssUssMaximum(int state) {
+ int idx = binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
+ }
+ }
+
+ public static final class ServiceState {
+ final ProcessStats mProcessStats;
+ final String mPackage;
+ ProcessState mProc;
+
+ int mActive = 1;
+
+ static final int SERVICE_STARTED = 0;
+ static final int SERVICE_BOUND = 1;
+ static final int SERVICE_EXEC = 2;
+ static final int SERVICE_COUNT = 3;
+
+ int[] mDurationsTable;
+ int mDurationsTableSize;
+
+ int mStartedCount;
+ public int mStartedState = STATE_NOTHING;
+ long mStartedStartTime;
+
+ int mBoundCount;
+ public int mBoundState = STATE_NOTHING;
+ long mBoundStartTime;
+
+ int mExecCount;
+ public int mExecState = STATE_NOTHING;
+ long mExecStartTime;
+
+ public ServiceState(ProcessStats processStats, String pkg, ProcessState proc) {
+ mProcessStats = processStats;
+ mPackage = pkg;
+ mProc = proc;
+ }
+
+ public void makeActive() {
+ mActive++;
+ }
+
+ public void makeInactive() {
+ /*
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.i(TAG, "Making " + this + " inactive", here);
+ */
+ mActive--;
+ }
+
+ public boolean isActive() {
+ return mActive > 0;
+ }
+
+ void resetSafely(long now) {
+ mDurationsTable = null;
+ mDurationsTableSize = 0;
+ mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
+ mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
+ mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
+ mStartedStartTime = mBoundStartTime = mExecStartTime = now;
+ }
+
+ void writeToParcel(Parcel out, long now) {
+ if (mStartedState != STATE_NOTHING) {
+ addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime);
+ mStartedStartTime = now;
+ }
+ if (mBoundState != STATE_NOTHING) {
+ addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime);
+ mBoundStartTime = now;
+ }
+ if (mExecState != STATE_NOTHING) {
+ addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime);
+ mExecStartTime = now;
+ }
+ out.writeInt(mDurationsTableSize);
+ for (int i=0; i<mDurationsTableSize; i++) {
+ if (DEBUG) Slog.i(TAG, "Writing service in " + mPackage + " dur #" + i + ": "
+ + printLongOffset(mDurationsTable[i]));
+ out.writeInt(mDurationsTable[i]);
+ }
+ out.writeInt(mStartedCount);
+ out.writeInt(mBoundCount);
+ out.writeInt(mExecCount);
+ }
+
+ boolean readFromParcel(Parcel in) {
+ if (DEBUG) Slog.d(TAG, "Reading durations table...");
+ mDurationsTable = mProcessStats.readTableFromParcel(in, mPackage, "service");
+ if (mDurationsTable == BAD_TABLE) {
+ return false;
+ }
+ mStartedCount = in.readInt();
+ mBoundCount = in.readInt();
+ mExecCount = in.readInt();
+ return true;
+ }
+
+ void addStateTime(int opType, int memFactor, long time) {
+ if (time > 0) {
+ int state = opType + (memFactor*SERVICE_COUNT);
+ int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+ int off;
+ if (idx >= 0) {
+ off = mDurationsTable[idx];
+ } else {
+ mProcessStats.mAddLongTable = mDurationsTable;
+ mProcessStats.mAddLongTableSize = mDurationsTableSize;
+ off = mProcessStats.addLongData(~idx, state, 1);
+ mDurationsTable = mProcessStats.mAddLongTable;
+ mDurationsTableSize = mProcessStats.mAddLongTableSize;
+ }
+ long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += time;
+ }
+ }
+
+ public void setStarted(boolean started, int memFactor, long now) {
+ if (mActive <= 0) {
+ throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
+ }
+ int state = started ? memFactor : STATE_NOTHING;
+ if (mStartedState != state) {
+ if (mStartedState != STATE_NOTHING) {
+ addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime);
+ } else if (started) {
+ mStartedCount++;
+ }
+ mStartedState = state;
+ mStartedStartTime = now;
+ if (mProc != null) {
+ mProc = mProc.pullFixedProc(mPackage);
+ if (started) {
+ mProc.incStartedServices(memFactor, now);
+ } else {
+ mProc.decStartedServices(memFactor, now);
+ }
+ }
+ }
+ }
+
+ public void setBound(boolean bound, int memFactor, long now) {
+ if (mActive <= 0) {
+ throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
+ }
+ int state = bound ? memFactor : STATE_NOTHING;
+ if (mBoundState != state) {
+ if (mBoundState != STATE_NOTHING) {
+ addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime);
+ } else if (bound) {
+ mBoundCount++;
+ }
+ mBoundState = state;
+ mBoundStartTime = now;
+ }
+ }
+
+ public void setExecuting(boolean executing, int memFactor, long now) {
+ if (mActive <= 0) {
+ throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
+ }
+ int state = executing ? memFactor : STATE_NOTHING;
+ if (mExecState != state) {
+ if (mExecState != STATE_NOTHING) {
+ addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime);
+ } else if (executing) {
+ mExecCount++;
+ }
+ mExecState = state;
+ mExecStartTime = now;
+ }
+ }
+
+ long getStartDuration(int opType, int memFactor, long now) {
+ switch (opType) {
+ case SERVICE_STARTED:
+ return getDuration(opType, mStartedState, mStartedStartTime, memFactor, now);
+ case SERVICE_BOUND:
+ return getDuration(opType, mBoundState, mBoundStartTime, memFactor, now);
+ case SERVICE_EXEC:
+ return getDuration(opType, mExecState, mExecStartTime, memFactor, now);
+ default:
+ throw new IllegalArgumentException("Bad opType: " + opType);
+ }
+ }
+
+
+ private long getDuration(int opType, int curState, long startTime, int memFactor,
+ long now) {
+ int state = opType + (memFactor*SERVICE_COUNT);
+ int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
+ long time = idx >= 0 ? mProcessStats.getLong(mDurationsTable[idx], 0) : 0;
+ if (curState == memFactor) {
+ time += now - startTime;
+ }
+ return time;
+ }
+ }
+
+ public static final class PackageState {
+ public final ArrayMap<String, ProcessState> mProcesses
+ = new ArrayMap<String, ProcessState>();
+ public final ArrayMap<String, ServiceState> mServices
+ = new ArrayMap<String, ServiceState>();
+ final int mUid;
+
+ public PackageState(int uid) {
+ mUid = uid;
+ }
+ }
+
+ static final class ProcessDataCollection {
+ final int[] screenStates;
+ final int[] memStates;
+ final int[] procStates;
+
+ long totalTime;
+ long numPss;
+ long minPss;
+ long avgPss;
+ long maxPss;
+ long minUss;
+ long avgUss;
+ long maxUss;
+
+ ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
+ screenStates = _screenStates;
+ memStates = _memStates;
+ procStates = _procStates;
+ }
+
+ void print(PrintWriter pw, long overallTime, boolean full) {
+ printPercent(pw, (double) totalTime / (double) overallTime);
+ if (numPss > 0) {
+ pw.print(" (");
+ printSizeValue(pw, minPss * 1024);
+ pw.print("-");
+ printSizeValue(pw, avgPss * 1024);
+ pw.print("-");
+ printSizeValue(pw, maxPss * 1024);
+ pw.print("/");
+ printSizeValue(pw, minUss * 1024);
+ pw.print("-");
+ printSizeValue(pw, avgUss * 1024);
+ pw.print("-");
+ printSizeValue(pw, maxUss * 1024);
+ if (full) {
+ pw.print(" over ");
+ pw.print(numPss);
+ }
+ pw.print(")");
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index f3aabe2..d61a48d 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -26,6 +26,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -251,9 +252,9 @@ public final class ActiveServices {
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
- ProcessTracker.ServiceState stracker = r.getTracker();
+ ProcessStats.ServiceState stracker = r.getTracker();
if (stracker != null) {
- stracker.setStarted(true, mAm.mProcessTracker.getMemFactorLocked(), r.lastActivity);
+ stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
@@ -274,7 +275,7 @@ public final class ActiveServices {
}
service.startRequested = false;
if (service.tracker != null) {
- service.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
+ service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
service.callStart = false;
@@ -374,7 +375,7 @@ public final class ActiveServices {
}
r.startRequested = false;
if (r.tracker != null) {
- r.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
+ r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
r.callStart = false;
@@ -516,9 +517,9 @@ public final class ActiveServices {
s.lastActivity = SystemClock.uptimeMillis();
if (!s.hasAutoCreateConnections()) {
// This is the first binding, let the tracker know.
- ProcessTracker.ServiceState stracker = s.getTracker();
+ ProcessStats.ServiceState stracker = s.getTracker();
if (stracker != null) {
- stracker.setBound(true, mAm.mProcessTracker.getMemFactorLocked(),
+ stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),
s.lastActivity);
}
}
@@ -844,9 +845,9 @@ public final class ActiveServices {
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
- ProcessTracker.ServiceState stracker = r.getTracker();
+ ProcessStats.ServiceState stracker = r.getTracker();
if (stracker != null) {
- stracker.setExecuting(true, mAm.mProcessTracker.getMemFactorLocked(), now);
+ stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
if (r.app.executingServices.size() == 0) {
@@ -1079,7 +1080,7 @@ public final class ActiveServices {
Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
if (app != null && app.thread != null) {
try {
- app.addPackage(r.appInfo.packageName, mAm.mProcessTracker);
+ app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (RemoteException e) {
@@ -1364,7 +1365,7 @@ public final class ActiveServices {
((ServiceRestarter)r.restarter).setService(null);
}
- int memFactor = mAm.mProcessTracker.getMemFactorLocked();
+ int memFactor = mAm.mProcessStats.getMemFactorLocked();
long now = SystemClock.uptimeMillis();
if (r.tracker != null) {
r.tracker.setStarted(false, memFactor, now);
@@ -1435,7 +1436,7 @@ public final class ActiveServices {
boolean hasAutoCreate = s.hasAutoCreateConnections();
if (!hasAutoCreate) {
if (s.tracker != null) {
- s.tracker.setBound(false, mAm.mProcessTracker.getMemFactorLocked(),
+ s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
}
@@ -1541,7 +1542,7 @@ public final class ActiveServices {
}
r.executeFg = false;
if (r.tracker != null) {
- r.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
+ r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (inStopping) {
r.tracker.makeInactive();
@@ -1566,7 +1567,7 @@ public final class ActiveServices {
mPendingServices.remove(i);
i--;
- proc.addPackage(sr.appInfo.packageName, mAm.mProcessTracker);
+ proc.addPackage(sr.appInfo.packageName, mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
}
@@ -1737,7 +1738,7 @@ public final class ActiveServices {
sr.isolatedProc = null;
sr.executeNesting = 0;
if (sr.tracker != null) {
- sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
+ sr.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
if (mStoppingServices.remove(sr)) {
@@ -1772,7 +1773,7 @@ public final class ActiveServices {
if (sr.pendingStarts.size() == 0) {
sr.startRequested = false;
if (sr.tracker != null) {
- sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
+ sr.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
if (!sr.hasAutoCreateConnections()) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cb1747f..1d26c2c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -30,10 +30,11 @@ import android.util.ArrayMap;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ProcessStats;
import com.android.internal.app.ResolverActivity;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.ProcessStats;
+import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
@@ -419,7 +420,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;
+ final ProcessStatsService mProcessStats;
/**
* The currently running isolated processes.
@@ -891,19 +892,19 @@ public final class ActivityManagerService extends ActivityManagerNative
= new ArrayList<ProcessChangeItem>();
/**
- * Runtime statistics collection thread. This object's lock is used to
+ * Runtime CPU use collection thread. This object's lock is used to
* protect all related state.
*/
- final Thread mProcessStatsThread;
+ final Thread mProcessCpuThread;
/**
* Used to collect process stats when showing not responding dialog.
- * Protected by mProcessStatsThread.
+ * Protected by mProcessCpuThread.
*/
- final ProcessStats mProcessStats = new ProcessStats(
+ final ProcessCpuTracker mProcessCpuTracker = new ProcessCpuTracker(
MONITOR_THREAD_CPU_USAGE);
final AtomicLong mLastCpuTime = new AtomicLong(0);
- final AtomicBoolean mProcessStatsMutexFree = new AtomicBoolean(true);
+ final AtomicBoolean mProcessCpuMutexFree = new AtomicBoolean(true);
long mLastWriteTime = 0;
@@ -1745,9 +1746,9 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- synchronized (mActivityManagerService.mProcessStatsThread) {
- pw.print(mActivityManagerService.mProcessStats.printCurrentLoad());
- pw.print(mActivityManagerService.mProcessStats.printCurrentState(
+ synchronized (mActivityManagerService.mProcessCpuThread) {
+ pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
+ pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
SystemClock.uptimeMillis()));
}
}
@@ -1769,7 +1770,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- mActivityManagerService.mProcessTracker.dump(fd, pw, args);
+ mActivityManagerService.mProcessStats.dump(fd, pw, args);
}
}
@@ -1795,7 +1796,7 @@ public final class ActivityManagerService extends ActivityManagerNative
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
- mProcessTracker = new ProcessTracker(this, new File(systemDir, "procstats"));
+ mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
mUsageStatsService = new UsageStatsService(new File(systemDir, "usagestats").toString());
mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"));
@@ -1816,14 +1817,14 @@ public final class ActivityManagerService extends ActivityManagerNative
mConfiguration.setLocale(Locale.getDefault());
mConfigurationSeq = mConfiguration.seq = 1;
- mProcessStats.init();
+ mProcessCpuTracker.init();
mCompatModePackages = new CompatModePackages(this, systemDir);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
- mProcessStatsThread = new Thread("ProcessStats") {
+ mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
while (true) {
@@ -1839,7 +1840,7 @@ public final class ActivityManagerService extends ActivityManagerNative
nextCpuDelay = nextWriteDelay;
}
if (nextCpuDelay > 0) {
- mProcessStatsMutexFree.set(true);
+ mProcessCpuMutexFree.set(true);
this.wait(nextCpuDelay);
}
}
@@ -1852,7 +1853,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
};
- mProcessStatsThread.start();
+ mProcessCpuThread.start();
}
@Override
@@ -1902,16 +1903,16 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mLastCpuTime.get() >= now - MONITOR_CPU_MIN_TIME) {
return;
}
- if (mProcessStatsMutexFree.compareAndSet(true, false)) {
- synchronized (mProcessStatsThread) {
- mProcessStatsThread.notify();
+ if (mProcessCpuMutexFree.compareAndSet(true, false)) {
+ synchronized (mProcessCpuThread) {
+ mProcessCpuThread.notify();
}
}
}
void updateCpuStatsNow() {
- synchronized (mProcessStatsThread) {
- mProcessStatsMutexFree.set(false);
+ synchronized (mProcessCpuThread) {
+ mProcessCpuMutexFree.set(false);
final long now = SystemClock.uptimeMillis();
boolean haveNewCpuStats = false;
@@ -1919,19 +1920,19 @@ public final class ActivityManagerService extends ActivityManagerNative
mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) {
mLastCpuTime.set(now);
haveNewCpuStats = true;
- mProcessStats.update();
- //Slog.i(TAG, mProcessStats.printCurrentState());
+ mProcessCpuTracker.update();
+ //Slog.i(TAG, mProcessCpu.printCurrentState());
//Slog.i(TAG, "Total CPU usage: "
- // + mProcessStats.getTotalCpuPercent() + "%");
+ // + mProcessCpu.getTotalCpuPercent() + "%");
// Slog the cpu usage if the property is set.
if ("true".equals(SystemProperties.get("events.cpu"))) {
- int user = mProcessStats.getLastUserTime();
- int system = mProcessStats.getLastSystemTime();
- int iowait = mProcessStats.getLastIoWaitTime();
- int irq = mProcessStats.getLastIrqTime();
- int softIrq = mProcessStats.getLastSoftIrqTime();
- int idle = mProcessStats.getLastIdleTime();
+ int user = mProcessCpuTracker.getLastUserTime();
+ int system = mProcessCpuTracker.getLastSystemTime();
+ int iowait = mProcessCpuTracker.getLastIoWaitTime();
+ int irq = mProcessCpuTracker.getLastIrqTime();
+ int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
+ int idle = mProcessCpuTracker.getLastIdleTime();
int total = user + system + iowait + irq + softIrq + idle;
if (total == 0) total = 1;
@@ -1946,7 +1947,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
+ long[] cpuSpeedTimes = mProcessCpuTracker.getLastCpuSpeedTimes();
final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
synchronized(bstats) {
synchronized(mPidsSelfLocked) {
@@ -1955,9 +1956,9 @@ public final class ActivityManagerService extends ActivityManagerNative
int perc = bstats.startAddingCpuLocked();
int totalUTime = 0;
int totalSTime = 0;
- final int N = mProcessStats.countStats();
+ final int N = mProcessCpuTracker.countStats();
for (int i=0; i<N; i++) {
- ProcessStats.Stats st = mProcessStats.getStats(i);
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
if (!st.working) {
continue;
}
@@ -2233,7 +2234,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// come up (we have a pid but not yet its thread), so keep it.
if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
// If this is a new package in the process, add the package to the list
- app.addPackage(info.packageName, mProcessTracker);
+ app.addPackage(info.packageName, mProcessStats);
return app;
}
@@ -2288,7 +2289,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
} else {
// If this is a new package in the process, add the package to the list
- app.addPackage(info.packageName, mProcessTracker);
+ app.addPackage(info.packageName, mProcessStats);
}
// If the system is not ready yet, then hold off on starting this
@@ -3368,7 +3369,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* @return file containing stack traces, or null if no dump file is configured
*/
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,
- ProcessStats processStats, SparseArray<Boolean> lastPids, String[] nativeProcs) {
+ ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
if (tracesPath == null || tracesPath.length() == 0) {
return null;
@@ -3393,12 +3394,12 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
- dumpStackTraces(tracesPath, firstPids, processStats, lastPids, nativeProcs);
+ dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativeProcs);
return tracesFile;
}
private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
- ProcessStats processStats, SparseArray<Boolean> lastPids, String[] nativeProcs) {
+ ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
// Use a FileObserver to detect when traces finish writing.
// The order of traces is considered important to maintain for legibility.
FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
@@ -3425,23 +3426,23 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Next measure CPU usage.
- if (processStats != null) {
- processStats.init();
+ if (processCpuTracker != null) {
+ processCpuTracker.init();
System.gc();
- processStats.update();
+ processCpuTracker.update();
try {
- synchronized (processStats) {
- processStats.wait(500); // measure over 1/2 second.
+ synchronized (processCpuTracker) {
+ processCpuTracker.wait(500); // measure over 1/2 second.
}
} catch (InterruptedException e) {
}
- processStats.update();
+ processCpuTracker.update();
// We'll take the stack crawls of just the top apps using CPU.
- final int N = processStats.countWorkingStats();
+ final int N = processCpuTracker.countWorkingStats();
int numProcs = 0;
for (int i=0; i<N && numProcs<5; i++) {
- ProcessStats.Stats stats = processStats.getWorkingStats(i);
+ ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
if (lastPids.indexOfKey(stats.pid) >= 0) {
numProcs++;
try {
@@ -3629,21 +3630,21 @@ public final class ActivityManagerService extends ActivityManagerNative
info.append("Parent: ").append(parent.shortComponentName).append("\n");
}
- final ProcessStats processStats = new ProcessStats(true);
+ final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
- File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids, null);
+ File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids, null);
String cpuInfo = null;
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
- synchronized (mProcessStatsThread) {
- cpuInfo = mProcessStats.printCurrentState(anrTime);
+ synchronized (mProcessCpuThread) {
+ cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
}
- info.append(processStats.printCurrentLoad());
+ info.append(processCpuTracker.printCurrentLoad());
info.append(cpuInfo);
}
- info.append(processStats.printCurrentState(anrTime));
+ info.append(processCpuTracker.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
if (tracesFile == null) {
@@ -4474,7 +4475,7 @@ public final class ActivityManagerService extends ActivityManagerNative
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
- app.resetPackageList(mProcessTracker);
+ app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false;
}
@@ -4566,7 +4567,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// an infinite loop of restarting processes...
Slog.w(TAG, "Exception thrown during bind!", e);
- app.resetPackageList(mProcessTracker);
+ app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
startProcessLocked(app, "bind fail", processName);
return false;
@@ -6782,7 +6783,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (DEBUG_MU)
Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
app.pubProviders.put(cpi.name, cpr);
- app.addPackage(cpi.applicationInfo.packageName, mProcessTracker);
+ app.addPackage(cpi.applicationInfo.packageName, mProcessStats);
ensurePackageDexOpt(cpi.applicationInfo.packageName);
}
}
@@ -7520,7 +7521,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ps = stats.getProcessStatsLocked(info.uid, proc);
}
return new ProcessRecord(ps, thread, info, proc, uid,
- mProcessTracker.getProcessStateLocked(info.packageName, info.uid, proc));
+ mProcessStats.getProcessStateLocked(info.packageName, info.uid, proc));
}
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
@@ -7660,7 +7661,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mUsageStatsService.shutdown();
mBatteryStatsService.shutdown();
synchronized (this) {
- mProcessTracker.shutdownLocked();
+ mProcessStats.shutdownLocked();
}
return timedout;
@@ -11665,7 +11666,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.crashing = false;
app.notResponding = false;
- app.resetPackageList(mProcessTracker);
+ app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
app.thread = null;
app.forcingToForeground = null;
@@ -14540,7 +14541,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " to " + app.curProcState);
app.setProcState = app.curProcState;
if (!doingAll) {
- setProcessTrackerState(app, mProcessTracker.getMemFactorLocked(), now);
+ setProcessTrackerState(app, mProcessStats.getMemFactorLocked(), now);
} else {
app.procStateChanged = true;
}
@@ -14818,17 +14819,17 @@ public final class ActivityManagerService extends ActivityManagerNative
int memFactor;
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
- memFactor = ProcessTracker.ADJ_MEM_FACTOR_CRITICAL;
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;
} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
- memFactor = ProcessTracker.ADJ_MEM_FACTOR_LOW;
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;
} else {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
- memFactor = ProcessTracker.ADJ_MEM_FACTOR_MODERATE;
+ memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;
}
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now);
- final int trackerMemFactor = mProcessTracker.getMemFactorLocked();
+ allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
+ final int trackerMemFactor = mProcessStats.getMemFactorLocked();
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -14916,9 +14917,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} else {
- allChanged = mProcessTracker.setMemFactorLocked(
- ProcessTracker.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
- final int trackerMemFactor = mProcessTracker.getMemFactorLocked();
+ allChanged = mProcessStats.setMemFactorLocked(
+ ProcessStats.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
+ final int trackerMemFactor = mProcessStats.getMemFactorLocked();
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
@@ -14951,14 +14952,14 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (allChanged) {
- requestPssAllProcsLocked(now, false, mProcessTracker.isMemFactorLowered());
+ requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());
}
- if (mProcessTracker.shouldWriteNowLocked(now)) {
+ if (mProcessStats.shouldWriteNowLocked(now)) {
mHandler.post(new Runnable() {
@Override public void run() {
synchronized (ActivityManagerService.this) {
- mProcessTracker.writeStateAsyncLocked();
+ mProcessStats.writeStateAsyncLocked();
}
}
});
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index cc1be98..3cbd345 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -893,8 +893,8 @@ final class ActivityStack {
if (prev.app != null && prev.cpuTimeAtResume > 0
&& mService.mBatteryStatsService.isOnBattery()) {
long diff;
- synchronized (mService.mProcessStatsThread) {
- diff = mService.mProcessStats.getCpuTimeForPid(prev.app.pid)
+ synchronized (mService.mProcessCpuThread) {
+ diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
- prev.cpuTimeAtResume;
}
if (diff > 0) {
@@ -902,7 +902,7 @@ final class ActivityStack {
synchronized (bsi) {
BatteryStatsImpl.Uid.Proc ps =
bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
- prev.info.packageName);
+ prev.info.packageName);
if (ps != null) {
ps.addForegroundTimeLocked(diff);
}
@@ -935,8 +935,8 @@ final class ActivityStack {
// TODO: To be more accurate, the mark should be before the onCreate,
// not after the onResume. But for subsequent starts, onResume is fine.
if (next.app != null) {
- synchronized (mService.mProcessStatsThread) {
- next.cpuTimeAtResume = mService.mProcessStats.getCpuTimeForPid(next.app.pid);
+ synchronized (mService.mProcessCpuThread) {
+ next.cpuTimeAtResume = mService.mProcessCpuTracker.getCpuTimeForPid(next.app.pid);
}
} else {
next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 1681c2d..633de8c 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1027,7 +1027,7 @@ public final class ActivityStackSupervisor {
if (app != null && app.thread != null) {
try {
- app.addPackage(r.info.packageName, mService.mProcessTracker);
+ app.addPackage(r.info.packageName, mService.mProcessStats);
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index c0140e4..cb4b8ff 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -797,7 +797,7 @@ public final class BroadcastQueue {
info.activityInfo.applicationInfo.uid);
if (app != null && app.thread != null) {
try {
- app.addPackage(info.activityInfo.packageName, mService.mProcessTracker);
+ app.addPackage(info.activityInfo.packageName, mService.mProcessStats);
processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 2b73b8a..f1a030e 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.util.ArraySet;
+import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import android.app.ActivityManager;
@@ -51,10 +52,10 @@ final class ProcessRecord {
final int uid; // uid of process; may be different from 'info' if isolated
final int userId; // user of process.
final String processName; // name of the process
- final ProcessTracker.ProcessState baseProcessTracker;
+ final ProcessStats.ProcessState baseProcessTracker;
// List of packages running in the process
- final ArrayMap<String, ProcessTracker.ProcessState> pkgList
- = new ArrayMap<String, ProcessTracker.ProcessState>();
+ final ArrayMap<String, ProcessStats.ProcessState> pkgList
+ = new ArrayMap<String, ProcessStats.ProcessState>();
IApplicationThread thread; // the actual proc... may be null only if
// 'persistent' is true (in which case we
// are in the process of launching the app)
@@ -350,7 +351,7 @@ final class ProcessRecord {
ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread,
ApplicationInfo _info, String _processName, int _uid,
- ProcessTracker.ProcessState tracker) {
+ ProcessStats.ProcessState tracker) {
batteryStats = _batteryStats;
info = _info;
isolated = _info.uid != _uid;
@@ -487,7 +488,7 @@ final class ProcessRecord {
/*
* Return true if package has been added false if not
*/
- public boolean addPackage(String pkg, ProcessTracker tracker) {
+ public boolean addPackage(String pkg, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName));
return true;
@@ -513,9 +514,9 @@ final class ProcessRecord {
/*
* Delete all packages from list except the package indicated in info
*/
- public void resetPackageList(ProcessTracker tracker) {
+ public void resetPackageList(ProcessStatsService tracker) {
long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessTracker.STATE_NOTHING,
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
tracker.getMemFactorLocked(), now, pkgList);
if (pkgList.size() != 1) {
pkgList.clear();
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
new file mode 100644
index 0000000..ee6f7ec
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -0,0 +1,714 @@
+/*
+ * 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.app.AppGlobals;
+import android.content.pm.IPackageManager;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.SparseArray;
+import com.android.internal.app.ProcessStats;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.locks.ReentrantLock;
+
+public final class ProcessStatsService {
+ static final String TAG = "ProcessStatsService";
+ static final boolean DEBUG = false;
+
+ // Most data is kept in a sparse data structure: an integer array which integer
+ // holds the type of the entry, and the identifier for a long array that data
+ // exists in and the offset into the array to find it. The constants below
+ // define the encoding of that data in an integer.
+
+ static final int MAX_HISTORIC_STATES = 4; // Maximum number of historic states we will keep.
+ static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
+ static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
+ static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
+ static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
+ static long COMMIT_PERIOD = 24*60*60*1000; // Commit current stats every day.
+
+ final Object mLock;
+ final File mBaseDir;
+ ProcessStats mProcessStats;
+ AtomicFile mFile;
+ boolean mCommitPending;
+ boolean mShuttingDown;
+ int mLastMemOnlyState = -1;
+ boolean mMemFactorLowered;
+
+ final ReentrantLock mWriteLock = new ReentrantLock();
+ final Object mPendingWriteLock = new Object();
+ AtomicFile mPendingWriteFile;
+ Parcel mPendingWrite;
+ boolean mPendingWriteCommitted;
+ long mLastWriteTime;
+
+ public ProcessStatsService(Object lock, File file) {
+ mLock = lock;
+ mBaseDir = file;
+ mBaseDir.mkdirs();
+ mProcessStats = new ProcessStats(true);
+ updateFile();
+ SystemProperties.addChangeCallback(new Runnable() {
+ @Override public void run() {
+ synchronized (mLock) {
+ if (mProcessStats.evaluateSystemProperties(false)) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
+ writeStateLocked(true, true);
+ mProcessStats.evaluateSystemProperties(true);
+ }
+ }
+ }
+ });
+ }
+
+ public ProcessStats.ProcessState getProcessStateLocked(String packageName,
+ int uid, String processName) {
+ return mProcessStats.getProcessStateLocked(packageName, uid, processName);
+ }
+
+ public ProcessStats.ServiceState getServiceStateLocked(String packageName, int uid,
+ String processName, String className) {
+ final ProcessStats.PackageState as = mProcessStats.getPackageStateLocked(packageName, uid);
+ ProcessStats.ServiceState ss = as.mServices.get(className);
+ if (ss != null) {
+ ss.makeActive();
+ return ss;
+ }
+ final ProcessStats.ProcessState ps = mProcessStats.getProcessStateLocked(packageName,
+ uid, processName);
+ ss = new ProcessStats.ServiceState(mProcessStats, packageName, ps);
+ as.mServices.put(className, ss);
+ return ss;
+ }
+
+ public boolean isMemFactorLowered() {
+ return mMemFactorLowered;
+ }
+
+ public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
+ mMemFactorLowered = memFactor < mLastMemOnlyState;
+ mLastMemOnlyState = memFactor;
+ if (screenOn) {
+ memFactor += ProcessStats.ADJ_SCREEN_ON;
+ }
+ if (memFactor != mProcessStats.mMemFactor) {
+ if (mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING) {
+ mProcessStats.mMemFactorDurations[mProcessStats.mMemFactor]
+ += now - mProcessStats.mStartTime;
+ }
+ mProcessStats.mMemFactor = memFactor;
+ mProcessStats.mStartTime = now;
+ ArrayMap<String, SparseArray<ProcessStats.PackageState>> pmap
+ = mProcessStats.mPackages.getMap();
+ for (int i=0; i<pmap.size(); i++) {
+ SparseArray<ProcessStats.PackageState> uids = pmap.valueAt(i);
+ for (int j=0; j<uids.size(); j++) {
+ ProcessStats.PackageState pkg = uids.valueAt(j);
+ ArrayMap<String, ProcessStats.ServiceState> services = pkg.mServices;
+ for (int k=0; k<services.size(); k++) {
+ ProcessStats.ServiceState service = services.valueAt(k);
+ if (service.isActive()) {
+ if (service.mStartedState != ProcessStats.STATE_NOTHING) {
+ service.setStarted(true, memFactor, now);
+ }
+ if (service.mBoundState != ProcessStats.STATE_NOTHING) {
+ service.setBound(true, memFactor, now);
+ }
+ if (service.mExecState != ProcessStats.STATE_NOTHING) {
+ service.setExecuting(true, memFactor, now);
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public int getMemFactorLocked() {
+ return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
+ }
+
+ public boolean shouldWriteNowLocked(long now) {
+ if (now > (mLastWriteTime+WRITE_PERIOD)) {
+ if (SystemClock.elapsedRealtime()
+ > (mProcessStats.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
+ mCommitPending = true;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public void shutdownLocked() {
+ Slog.w(TAG, "Writing process stats before shutdown...");
+ mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
+ writeStateSyncLocked();
+ mShuttingDown = true;
+ }
+
+ public void writeStateAsyncLocked() {
+ writeStateLocked(false);
+ }
+
+ public void writeStateSyncLocked() {
+ writeStateLocked(true);
+ }
+
+ private void writeStateLocked(boolean sync) {
+ if (mShuttingDown) {
+ return;
+ }
+ boolean commitPending = mCommitPending;
+ mCommitPending = false;
+ writeStateLocked(sync, commitPending);
+ }
+
+ public void writeStateLocked(boolean sync, final boolean commit) {
+ synchronized (mPendingWriteLock) {
+ long now = SystemClock.uptimeMillis();
+ if (mPendingWrite == null || !mPendingWriteCommitted) {
+ mPendingWrite = Parcel.obtain();
+ mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+ if (commit) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+ }
+ mProcessStats.writeToParcel(mPendingWrite);
+ mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
+ mPendingWriteCommitted = commit;
+ }
+ if (commit) {
+ mProcessStats.resetSafely();
+ updateFile();
+ }
+ mLastWriteTime = SystemClock.uptimeMillis();
+ Slog.i(TAG, "Prepared write state in " + (SystemClock.uptimeMillis()-now) + "ms");
+ if (!sync) {
+ BackgroundThread.getHandler().post(new Runnable() {
+ @Override public void run() {
+ performWriteState();
+ }
+ });
+ return;
+ }
+ }
+
+ performWriteState();
+ }
+
+ private void updateFile() {
+ mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
+ + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
+ mLastWriteTime = SystemClock.uptimeMillis();
+ }
+
+ void performWriteState() {
+ if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
+ Parcel data;
+ AtomicFile file;
+ synchronized (mPendingWriteLock) {
+ data = mPendingWrite;
+ file = mPendingWriteFile;
+ mPendingWriteCommitted = false;
+ if (data == null) {
+ return;
+ }
+ mPendingWrite = null;
+ mPendingWriteFile = null;
+ mWriteLock.lock();
+ }
+
+ FileOutputStream stream = null;
+ try {
+ stream = file.startWrite();
+ stream.write(data.marshall());
+ stream.flush();
+ file.finishWrite(stream);
+ if (DEBUG) Slog.d(TAG, "Write completed successfully!");
+ } catch (IOException e) {
+ Slog.w(TAG, "Error writing process statistics", e);
+ file.failWrite(stream);
+ } finally {
+ data.recycle();
+ trimHistoricStatesWriteLocked();
+ mWriteLock.unlock();
+ }
+ }
+
+ static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+ int pos = 0;
+ int avail = stream.available();
+ byte[] data = new byte[avail];
+ while (true) {
+ int amt = stream.read(data, pos, data.length-pos);
+ //Log.i("foo", "Read " + amt + " bytes at " + pos
+ // + " of avail " + data.length);
+ if (amt <= 0) {
+ //Log.i("foo", "**** FINISHED READING: pos=" + pos
+ // + " len=" + data.length);
+ return data;
+ }
+ pos += amt;
+ avail = stream.available();
+ if (avail > data.length-pos) {
+ byte[] newData = new byte[pos+avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ }
+
+ boolean readLocked(ProcessStats stats, AtomicFile file) {
+ try {
+ FileInputStream stream = file.openRead();
+
+ byte[] raw = readFully(stream);
+ Parcel in = Parcel.obtain();
+ in.unmarshall(raw, 0, raw.length);
+ in.setDataPosition(0);
+ stream.close();
+
+ stats.readFromParcel(in);
+ if (stats.mReadError != null) {
+ Slog.w(TAG, "Ignoring existing stats; " + stats.mReadError);
+ if (DEBUG) {
+ ArrayMap<String, SparseArray<ProcessStats.ProcessState>> procMap
+ = stats.mProcesses.getMap();
+ final int NPROC = procMap.size();
+ for (int ip=0; ip<NPROC; ip++) {
+ Slog.w(TAG, "Process: " + procMap.keyAt(ip));
+ SparseArray<ProcessStats.ProcessState> uids = procMap.valueAt(ip);
+ final int NUID = uids.size();
+ for (int iu=0; iu<NUID; iu++) {
+ Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
+ }
+ }
+ ArrayMap<String, SparseArray<ProcessStats.PackageState>> pkgMap
+ = stats.mPackages.getMap();
+ final int NPKG = pkgMap.size();
+ for (int ip=0; ip<NPKG; ip++) {
+ Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
+ SparseArray<ProcessStats.PackageState> uids = pkgMap.valueAt(ip);
+ final int NUID = uids.size();
+ for (int iu=0; iu<NUID; iu++) {
+ Slog.w(TAG, " Uid: " + uids.keyAt(iu));
+ ProcessStats.PackageState pkgState = uids.valueAt(iu);
+ final int NPROCS = pkgState.mProcesses.size();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ Slog.w(TAG, " Process " + pkgState.mProcesses.keyAt(iproc)
+ + ": " + pkgState.mProcesses.valueAt(iproc));
+ }
+ final int NSRVS = pkgState.mServices.size();
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ Slog.w(TAG, " Service " + pkgState.mServices.keyAt(isvc)
+ + ": " + pkgState.mServices.valueAt(isvc));
+ }
+ }
+ }
+ }
+ return false;
+ }
+ } catch (Throwable e) {
+ stats.mReadError = "caught exception: " + e;
+ Slog.e(TAG, "Error reading process statistics", e);
+ return false;
+ }
+ return true;
+ }
+
+ private ArrayList<String> getCommittedFiles(int minNum, boolean inclAll) {
+ File[] files = mBaseDir.listFiles();
+ if (files == null || files.length <= minNum) {
+ return null;
+ }
+ ArrayList<String> filesArray = new ArrayList<String>(files.length);
+ String currentFile = mFile.getBaseFile().getPath();
+ if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
+ for (int i=0; i<files.length; i++) {
+ File file = files[i];
+ String fileStr = file.getPath();
+ if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
+ if (!inclAll && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
+ if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
+ continue;
+ }
+ if (fileStr.equals(currentFile)) {
+ if (DEBUG) Slog.d(TAG, "Skipping: current stats");
+ continue;
+ }
+ filesArray.add(fileStr);
+ }
+ Collections.sort(filesArray);
+ return filesArray;
+ }
+
+ public void trimHistoricStatesWriteLocked() {
+ ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, true);
+ if (filesArray == null) {
+ return;
+ }
+ while (filesArray.size() > MAX_HISTORIC_STATES) {
+ String file = filesArray.remove(0);
+ Slog.i(TAG, "Pruning old procstats: " + file);
+ (new File(file)).delete();
+ }
+ }
+
+ boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
+ boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
+ boolean sepProcStates, int[] procStates, long now, String reqPackage) {
+ ArrayList<ProcessStats.ProcessState> procs = mProcessStats.collectProcessesLocked(
+ screenStates, memStates, procStates, now, reqPackage);
+ if (procs.size() > 0) {
+ if (header != null) {
+ pw.println(header);
+ }
+ ProcessStats.dumpProcessListCsv(pw, procs, sepScreenStates, screenStates,
+ sepMemStates, memStates, sepProcStates, procStates, now);
+ return true;
+ }
+ return false;
+ }
+
+ 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;
+ }
+
+ static private void dumpHelp(PrintWriter pw) {
+ pw.println("Process stats (procstats) dump options:");
+ pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
+ pw.println(" [--details] [--current] [--commit] [--write] [-h] [<package.name>]");
+ pw.println(" --checkin: perform a checkin: print and delete old committed states.");
+ pw.println(" --c: print only state in checkin format.");
+ 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(" --details: dump all execution details, not just summary.");
+ pw.println(" --current: only dump current state.");
+ pw.println(" --commit: commit current stats to disk and reset to start new stats.");
+ pw.println(" --write: write current in-memory stats to disk.");
+ pw.println(" --read: replace current stats with last-written stats.");
+ pw.println(" -a: print everything.");
+ pw.println(" -h: print this help text.");
+ pw.println(" <package.name>: optional name of package to filter output by.");
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final long now = SystemClock.uptimeMillis();
+
+ boolean isCheckin = false;
+ boolean isCompact = false;
+ boolean isCsv = false;
+ boolean currentOnly = false;
+ boolean dumpDetails = false;
+ boolean dumpAll = false;
+ String reqPackage = null;
+ boolean csvSepScreenStats = false;
+ int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
+ boolean csvSepMemStats = false;
+ int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
+ boolean csvSepProcStats = true;
+ int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
+ if (args != null) {
+ for (int i=0; i<args.length; i++) {
+ String arg = args[i];
+ if ("--checkin".equals(arg)) {
+ isCheckin = true;
+ } else if ("-c".equals(arg)) {
+ isCompact = 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;
+ }
+ boolean[] sep = new boolean[1];
+ String[] error = new String[1];
+ csvScreenStats = parseStateList(ProcessStats.ADJ_SCREEN_NAMES_CSV, ProcessStats.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(ProcessStats.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(ProcessStats.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 ("--details".equals(arg)) {
+ dumpDetails = true;
+ } else if ("--current".equals(arg)) {
+ currentOnly = true;
+ } else if ("--commit".equals(arg)) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
+ writeStateLocked(true, true);
+ pw.println("Process stats committed.");
+ return;
+ } else if ("--write".equals(arg)) {
+ writeStateSyncLocked();
+ pw.println("Process stats written.");
+ return;
+ } else if ("--read".equals(arg)) {
+ readLocked(mProcessStats, mFile);
+ pw.println("Process stats read.");
+ return;
+ } else if ("-h".equals(arg)) {
+ dumpHelp(pw);
+ return;
+ } else if ("-a".equals(arg)) {
+ dumpDetails = true;
+ dumpAll = true;
+ } 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 {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
+ reqPackage = arg;
+ // Include all details, since we know we are only going to
+ // be dumping a smaller set of data. In fact only the details
+ // container per-package data, so that are needed to be able
+ // to dump anything at all when filtering by package.
+ dumpDetails = true;
+ }
+ } catch (RemoteException e) {
+ }
+ if (reqPackage == null) {
+ pw.println("Unknown package: " + arg);
+ dumpHelp(pw);
+ return;
+ }
+ }
+ }
+ }
+
+ if (isCsv) {
+ pw.print("Processes running summed over");
+ if (!csvSepScreenStats) {
+ for (int i=0; i<csvScreenStats.length; i++) {
+ pw.print(" ");
+ ProcessStats.printScreenLabelCsv(pw, csvScreenStats[i]);
+ }
+ }
+ if (!csvSepMemStats) {
+ for (int i=0; i<csvMemStats.length; i++) {
+ pw.print(" ");
+ ProcessStats.printMemLabelCsv(pw, csvMemStats[i]);
+ }
+ }
+ if (!csvSepProcStats) {
+ for (int i=0; i<csvProcStats.length; i++) {
+ pw.print(" ");
+ pw.print(ProcessStats.STATE_NAMES_CSV[csvProcStats[i]]);
+ }
+ }
+ pw.println();
+ synchronized (mLock) {
+ dumpFilteredProcessesCsvLocked(pw, null,
+ csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
+ csvSepProcStats, csvProcStats, now, reqPackage);
+ /*
+ dumpFilteredProcessesCsvLocked(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);
+ dumpFilteredProcessesCsvLocked(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;
+ }
+
+ boolean sepNeeded = false;
+ if (!currentOnly || isCheckin) {
+ mWriteLock.lock();
+ try {
+ ArrayList<String> files = getCommittedFiles(0, !isCheckin);
+ if (files != null) {
+ for (int i=0; i<files.size(); i++) {
+ if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
+ try {
+ AtomicFile file = new AtomicFile(new File(files.get(i)));
+ ProcessStats processStats = new ProcessStats(false);
+ readLocked(processStats, file);
+ if (processStats.mReadError != null) {
+ if (isCheckin || isCompact) pw.print("err,");
+ pw.print("Failure reading "); pw.print(files.get(i));
+ pw.print("; "); pw.println(processStats.mReadError);
+ if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
+ (new File(files.get(i))).delete();
+ continue;
+ }
+ String fileStr = file.getBaseFile().getPath();
+ boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
+ if (isCheckin || isCompact) {
+ // Don't really need to lock because we uniquely own this object.
+ processStats.dumpCheckinLocked(pw, reqPackage);
+ } else {
+ if (sepNeeded) {
+ pw.println();
+ } else {
+ sepNeeded = true;
+ }
+ pw.print("COMMITTED STATS FROM ");
+ pw.print(processStats.mTimePeriodStartClockStr);
+ if (checkedIn) pw.print(" (checked in)");
+ pw.println(":");
+ // Don't really need to lock because we uniquely own this object.
+ if (dumpDetails) {
+ processStats.dumpLocked(pw, reqPackage, now, dumpAll);
+ } else {
+ processStats.dumpSummaryLocked(pw, reqPackage, now);
+ }
+ }
+ if (isCheckin) {
+ // Rename file suffix to mark that it has checked in.
+ file.getBaseFile().renameTo(new File(
+ fileStr + STATE_FILE_CHECKIN_SUFFIX));
+ }
+ } catch (Throwable e) {
+ pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
+ e.printStackTrace(pw);
+ }
+ }
+ }
+ } finally {
+ mWriteLock.unlock();
+ }
+ }
+ if (!isCheckin) {
+ synchronized (mLock) {
+ if (isCompact) {
+ mProcessStats.dumpCheckinLocked(pw, reqPackage);
+ } else {
+ if (sepNeeded) {
+ pw.println();
+ pw.println("CURRENT STATS:");
+ }
+ if (dumpDetails) {
+ mProcessStats.dumpLocked(pw, reqPackage, now, dumpAll);
+ if (dumpAll) {
+ pw.print(" mFile="); pw.println(mFile.getBaseFile());
+ }
+ } else {
+ mProcessStats.dumpSummaryLocked(pw, reqPackage, now);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
deleted file mode 100644
index d78fd5c..0000000
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ /dev/null
@@ -1,3126 +0,0 @@
-/*
- * 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.app.AppGlobals;
-import android.content.pm.IPackageManager;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.text.format.DateFormat;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.TimeUtils;
-import android.webkit.WebViewFactory;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.ArrayUtils;
-import com.android.server.ProcessMap;
-import dalvik.system.VMRuntime;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Objects;
-import java.util.concurrent.locks.ReentrantLock;
-
-public final class ProcessTracker {
- static final String TAG = "ProcessTracker";
- static final boolean DEBUG = false;
-
- 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_HEAVY_WEIGHT = 5;
- public static final int STATE_SERVICE = 6;
- public static final int STATE_SERVICE_RESTARTING = 7;
- public static final int STATE_RECEIVER = 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;
-
- static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
- STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
- STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER,
- STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
- STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
- };
-
- static final int[] NON_CACHED_PROC_STATES = new int[] { STATE_PERSISTENT,
- STATE_TOP, STATE_IMPORTANT_FOREGROUND,
- STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
- STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HOME
- };
-
- 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_COUNT = PSS_USS_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;
-
- static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
- static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, ADJ_MEM_FACTOR_MODERATE,
- ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
-
- // Most data is kept in a sparse data structure: an integer array which integer
- // holds the type of the entry, and the identifier for a long array that data
- // exists in and the offset into the array to find it. The constants below
- // define the encoding of that data in an integer.
-
- // Where the "type"/"state" part of the data appears in an offset integer.
- static int OFFSET_TYPE_SHIFT = 0;
- static int OFFSET_TYPE_MASK = 0xff;
-
- // Where the "which array" part of the data appears in an offset integer.
- static int OFFSET_ARRAY_SHIFT = 8;
- static int OFFSET_ARRAY_MASK = 0xff;
-
- // Where the "index into array" part of the data appears in an offset integer.
- static int OFFSET_INDEX_SHIFT = 16;
- static int OFFSET_INDEX_MASK = 0xffff;
-
- static final String[] STATE_NAMES = new String[] {
- "Persistent", "Top ", "Imp Fg ", "Imp Bg ",
- "Backup ", "Heavy Wght", "Service ", "Service Rs",
- "Receiver ", "Home ",
- "Last Act ", "Cch Act ", "Cch CliAct", "Cch Empty "
- };
-
- 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", "impfg", "impbg", "backup", "heavy",
- "service", "service-rs", "receiver", "home", "lastact",
- "cch-activity", "cch-aclient", "cch-empty"
- };
-
- static final String[] ADJ_SCREEN_TAGS = new String[] {
- "0", "1"
- };
-
- static final String[] ADJ_MEM_TAGS = new String[] {
- "n", "m", "l", "c"
- };
-
- static final String[] STATE_TAGS = new String[] {
- "p", "t", "f", "b", "u", "w",
- "s", "x", "r", "h", "l", "a", "c", "e"
- };
-
- // Map from process states to the states we track.
- static final int[] PROCESS_STATE_TO_STATE = new int[] {
- STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
- STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
- STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
- STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
- STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
- STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
- STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
- STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER
- STATE_HOME, // ActivityManager.PROCESS_STATE_HOME
- STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
- STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
- STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
- STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
- };
-
- static final String CSV_SEP = "\t";
-
- static final int MAX_HISTORIC_STATES = 4; // Maximum number of historic states we will keep.
- static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
- static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
- static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
- static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
- static long COMMIT_PERIOD = 24*60*60*1000; // Commit current stats every day.
-
- final Object mLock;
- final File mBaseDir;
- State mState;
- boolean mCommitPending;
- boolean mShuttingDown;
- int mLastMemOnlyState = -1;
- boolean mMemFactorLowered;
-
- final ReentrantLock mWriteLock = new ReentrantLock();
-
- public static final class ProcessState {
- final State mState;
- final ProcessState mCommonProcess;
- final String mPackage;
- final int mUid;
- final String mName;
-
- int[] mDurationsTable;
- int mDurationsTableSize;
-
- //final long[] mDurations = new long[STATE_COUNT*ADJ_COUNT];
- int mCurState = STATE_NOTHING;
- long mStartTime;
-
- int mLastPssState = STATE_NOTHING;
- long mLastPssTime;
- int[] mPssTable;
- int mPssTableSize;
-
- int mNumStartedServices;
-
- int mNumExcessiveWake;
- int mNumExcessiveCpu;
-
- boolean mMultiPackage;
-
- long mTmpTotalTime;
-
- /**
- * 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 = this;
- 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);
- if (mDurationsTable != null) {
- mState.mAddLongTable = new int[mDurationsTable.length];
- mState.mAddLongTableSize = 0;
- for (int i=0; i<mDurationsTableSize; i++) {
- int origEnt = mDurationsTable[i];
- int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mState.addLongData(i, type, 1);
- mState.mAddLongTable[i] = newOff | type;
- mState.setLong(newOff, 0, mState.getLong(origEnt, 0));
- }
- pnew.mDurationsTable = mState.mAddLongTable;
- pnew.mDurationsTableSize = mState.mAddLongTableSize;
- }
- if (mPssTable != null) {
- mState.mAddLongTable = new int[mPssTable.length];
- mState.mAddLongTableSize = 0;
- for (int i=0; i<mPssTableSize; i++) {
- int origEnt = mPssTable[i];
- int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mState.addLongData(i, type, PSS_COUNT);
- mState.mAddLongTable[i] = newOff | type;
- for (int j=0; j<PSS_COUNT; j++) {
- mState.setLong(newOff, j, mState.getLong(origEnt, j));
- }
- }
- pnew.mPssTable = mState.mAddLongTable;
- pnew.mPssTableSize = mState.mAddLongTableSize;
- }
- pnew.mNumExcessiveWake = mNumExcessiveWake;
- pnew.mNumExcessiveCpu = mNumExcessiveCpu;
- pnew.mNumStartedServices = mNumStartedServices;
- return pnew;
- }
-
- void resetSafely(long now) {
- mDurationsTable = null;
- mDurationsTableSize = 0;
- mStartTime = now;
- mLastPssState = STATE_NOTHING;
- mLastPssTime = 0;
- mPssTable = null;
- mPssTableSize = 0;
- mNumExcessiveWake = 0;
- mNumExcessiveCpu = 0;
- }
-
- void writeToParcel(Parcel out, long now) {
- commitStateTime(now);
- out.writeInt(mMultiPackage ? 1 : 0);
- out.writeInt(mDurationsTableSize);
- for (int i=0; i<mDurationsTableSize; i++) {
- if (DEBUG) Slog.i(TAG, "Writing in " + mName + " dur #" + i + ": "
- + State.printLongOffset(mDurationsTable[i]));
- out.writeInt(mDurationsTable[i]);
- }
- out.writeInt(mPssTableSize);
- for (int i=0; i<mPssTableSize; i++) {
- if (DEBUG) Slog.i(TAG, "Writing in " + mName + " pss #" + i + ": "
- + State.printLongOffset(mPssTable[i]));
- out.writeInt(mPssTable[i]);
- }
- out.writeInt(mNumExcessiveWake);
- out.writeInt(mNumExcessiveCpu);
- }
-
- boolean readFromParcel(Parcel in, boolean fully) {
- boolean multiPackage = in.readInt() != 0;
- if (fully) {
- mMultiPackage = multiPackage;
- }
- if (DEBUG) Slog.d(TAG, "Reading durations table...");
- mDurationsTable = mState.readTableFromParcel(in, mName, "durations");
- if (mDurationsTable == State.BAD_TABLE) {
- return false;
- }
- mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
- if (DEBUG) Slog.d(TAG, "Reading pss table...");
- mPssTable = mState.readTableFromParcel(in, mName, "pss");
- if (mPssTable == State.BAD_TABLE) {
- return false;
- }
- mPssTableSize = mPssTable != null ? mPssTable.length : 0;
- mNumExcessiveWake = in.readInt();
- mNumExcessiveCpu = in.readInt();
- return true;
- }
-
- /**
- * Update the current state of the given list of processes.
- *
- * @param state Current ActivityManager.PROCESS_STATE_*
- * @param memFactor Current mem factor constant.
- * @param now Current time.
- * @param pkgList Processes to update.
- */
- public void setState(int state, int memFactor, long now,
- ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
- if (state < 0) {
- state = mNumStartedServices > 0
- ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
- } else {
- state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
- }
-
- // First update the common process.
- mCommonProcess.setState(state, now);
-
- // If the common process is not multi-package, there is nothing else to do.
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- if (pkgList != null) {
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).setState(state, now);
- }
- }
- }
-
- void setState(int state, long now) {
- if (mCurState != state) {
- //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
- commitStateTime(now);
- mCurState = state;
- }
- }
-
- void commitStateTime(long now) {
- if (mCurState != STATE_NOTHING) {
- long dur = now - mStartTime;
- if (dur > 0) {
- int idx = State.binarySearch(mDurationsTable, mDurationsTableSize, mCurState);
- int off;
- if (idx >= 0) {
- off = mDurationsTable[idx];
- } else {
- mState.mAddLongTable = mDurationsTable;
- mState.mAddLongTableSize = mDurationsTableSize;
- off = mState.addLongData(~idx, mCurState, 1);
- mDurationsTable = mState.mAddLongTable;
- mDurationsTableSize = mState.mAddLongTableSize;
- }
- long[] longs = mState.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
- }
- }
- mStartTime = now;
- }
-
- void incStartedServices(int memFactor, long now) {
- if (mCommonProcess != this) {
- mCommonProcess.incStartedServices(memFactor, now);
- }
- mNumStartedServices++;
- if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
- setState(STATE_NOTHING, memFactor, now, null);
- }
- }
-
- void decStartedServices(int memFactor, long now) {
- if (mCommonProcess != this) {
- mCommonProcess.decStartedServices(memFactor, now);
- }
- mNumStartedServices--;
- if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
- setState(STATE_NOTHING, memFactor, now, null);
- } else if (mNumStartedServices < 0) {
- throw new IllegalStateException("Proc started services underrun: pkg="
- + mPackage + " uid=" + mUid + " name=" + mName);
- }
- }
-
- public void addPss(long pss, long uss, boolean always) {
- if (!always) {
- if (mLastPssState == mCurState && SystemClock.uptimeMillis()
- < (mLastPssTime+(30*1000))) {
- return;
- }
- }
- mLastPssState = mCurState;
- mLastPssTime = SystemClock.uptimeMillis();
- if (mCurState != STATE_NOTHING) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, mCurState);
- int off;
- if (idx >= 0) {
- off = mPssTable[idx];
- } else {
- mState.mAddLongTable = mPssTable;
- mState.mAddLongTableSize = mPssTableSize;
- off = mState.addLongData(~idx, mCurState, PSS_COUNT);
- mPssTable = mState.mAddLongTable;
- mPssTableSize = mState.mAddLongTableSize;
- }
- long[] longs = mState.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
- long count = longs[idx+PSS_SAMPLE_COUNT];
- if (count == 0) {
- longs[idx+PSS_SAMPLE_COUNT] = 1;
- longs[idx+PSS_MINIMUM] = pss;
- longs[idx+PSS_AVERAGE] = pss;
- longs[idx+PSS_MAXIMUM] = pss;
- longs[idx+PSS_USS_MINIMUM] = uss;
- longs[idx+PSS_USS_AVERAGE] = uss;
- longs[idx+PSS_USS_MAXIMUM] = uss;
- } else {
- longs[idx+PSS_SAMPLE_COUNT] = count+1;
- if (longs[idx+PSS_MINIMUM] > pss) {
- longs[idx+PSS_MINIMUM] = pss;
- }
- longs[idx+PSS_AVERAGE] = (long)(
- ((longs[idx+PSS_AVERAGE]*(double)count)+pss) / (count+1) );
- if (longs[idx+PSS_MAXIMUM] < pss) {
- longs[idx+PSS_MAXIMUM] = pss;
- }
- if (longs[idx+PSS_USS_MINIMUM] > uss) {
- longs[idx+PSS_USS_MINIMUM] = uss;
- }
- longs[idx+PSS_USS_AVERAGE] = (long)(
- ((longs[idx+PSS_USS_AVERAGE]*(double)count)+uss) / (count+1) );
- if (longs[idx+PSS_USS_MAXIMUM] < uss) {
- longs[idx+PSS_USS_MAXIMUM] = uss;
- }
- }
- }
- }
-
- public void reportExcessiveWake(ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
- mCommonProcess.mNumExcessiveWake++;
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).mNumExcessiveWake++;
- }
- }
-
- public void reportExcessiveCpu(ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
- mCommonProcess.mNumExcessiveCpu++;
- if (!mCommonProcess.mMultiPackage) {
- return;
- }
-
- for (int ip=pkgList.size()-1; ip>=0; ip--) {
- pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
- }
- }
-
- ProcessState pullFixedProc(String pkgName) {
- if (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.
- ProcessState proc = mState.mPackages.get(pkgName, mUid).mProcesses.get(mName);
- if (proc == null) {
- throw new IllegalStateException("Didn't create per-package process");
- }
- return proc;
- }
- return this;
- }
-
- private ProcessState pullFixedProc(ArrayMap<String, ProcessTracker.ProcessState> pkgList,
- int index) {
- ProcessState proc = pkgList.valueAt(index);
- 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(index),
- proc.mUid).mProcesses.get(proc.mName);
- if (proc == null) {
- throw new IllegalStateException("Didn't create per-package process");
- }
- pkgList.setValueAt(index, proc);
- }
- return proc;
- }
-
- long getDuration(int state, long now) {
- int idx = State.binarySearch(mDurationsTable, mDurationsTableSize, state);
- long time = idx >= 0 ? mState.getLong(mDurationsTable[idx], 0) : 0;
- if (mCurState == state) {
- time += now - mStartTime;
- }
- return time;
- }
-
- long getPssSampleCount(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
- }
-
- long getPssMinimum(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
- }
-
- long getPssAverage(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
- }
-
- long getPssMaximum(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
- }
-
- long getPssUssMinimum(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
- }
-
- long getPssUssAverage(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
- }
-
- long getPssUssMaximum(int state) {
- int idx = State.binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
- }
- }
-
- public static final class ServiceState {
- final State mState;
- final String mPackage;
- ProcessState mProc;
-
- int mActive = 1;
-
- static final int SERVICE_STARTED = 0;
- static final int SERVICE_BOUND = 1;
- static final int SERVICE_EXEC = 2;
- static final int SERVICE_COUNT = 3;
-
- int[] mDurationsTable;
- int mDurationsTableSize;
-
- int mStartedCount;
- int mStartedState = STATE_NOTHING;
- long mStartedStartTime;
-
- int mBoundCount;
- int mBoundState = STATE_NOTHING;
- long mBoundStartTime;
-
- int mExecCount;
- int mExecState = STATE_NOTHING;
- long mExecStartTime;
-
- ServiceState(State state, String pkg, ProcessState proc) {
- mState = state;
- mPackage = pkg;
- mProc = proc;
- }
-
- void makeActive() {
- mActive++;
- }
-
- void makeInactive() {
- /*
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.i(TAG, "Making " + this + " inactive", here);
- */
- mActive--;
- }
-
- boolean isActive() {
- return mActive > 0;
- }
-
- void resetSafely(long now) {
- mDurationsTable = null;
- mDurationsTableSize = 0;
- mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
- mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
- mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
- mStartedStartTime = mBoundStartTime = mExecStartTime = now;
- }
-
- void writeToParcel(Parcel out, long now) {
- if (mStartedState != STATE_NOTHING) {
- addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime);
- mStartedStartTime = now;
- }
- if (mBoundState != STATE_NOTHING) {
- addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime);
- mBoundStartTime = now;
- }
- if (mExecState != STATE_NOTHING) {
- addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime);
- mExecStartTime = now;
- }
- out.writeInt(mDurationsTableSize);
- for (int i=0; i<mDurationsTableSize; i++) {
- if (DEBUG) Slog.i(TAG, "Writing service in " + mPackage + " dur #" + i + ": "
- + State.printLongOffset(mDurationsTable[i]));
- out.writeInt(mDurationsTable[i]);
- }
- out.writeInt(mStartedCount);
- out.writeInt(mBoundCount);
- out.writeInt(mExecCount);
- }
-
- boolean readFromParcel(Parcel in) {
- if (DEBUG) Slog.d(TAG, "Reading durations table...");
- mDurationsTable = mState.readTableFromParcel(in, mPackage, "service");
- if (mDurationsTable == State.BAD_TABLE) {
- return false;
- }
- mStartedCount = in.readInt();
- mBoundCount = in.readInt();
- mExecCount = in.readInt();
- return true;
- }
-
- void addStateTime(int opType, int memFactor, long time) {
- if (time > 0) {
- int state = opType + (memFactor*SERVICE_COUNT);
- int idx = State.binarySearch(mDurationsTable, mDurationsTableSize, state);
- int off;
- if (idx >= 0) {
- off = mDurationsTable[idx];
- } else {
- mState.mAddLongTable = mDurationsTable;
- mState.mAddLongTableSize = mDurationsTableSize;
- off = mState.addLongData(~idx, state, 1);
- mDurationsTable = mState.mAddLongTable;
- mDurationsTableSize = mState.mAddLongTableSize;
- }
- long[] longs = mState.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += time;
- }
- }
-
- public void setStarted(boolean started, int memFactor, long now) {
- if (mActive <= 0) {
- throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
- }
- int state = started ? memFactor : STATE_NOTHING;
- if (mStartedState != state) {
- if (mStartedState != STATE_NOTHING) {
- addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime);
- } else if (started) {
- mStartedCount++;
- }
- mStartedState = state;
- mStartedStartTime = now;
- if (mProc != null) {
- mProc = mProc.pullFixedProc(mPackage);
- if (started) {
- mProc.incStartedServices(memFactor, now);
- } else {
- mProc.decStartedServices(memFactor, now);
- }
- }
- }
- }
-
- public void setBound(boolean bound, int memFactor, long now) {
- if (mActive <= 0) {
- throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
- }
- int state = bound ? memFactor : STATE_NOTHING;
- if (mBoundState != state) {
- if (mBoundState != STATE_NOTHING) {
- addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime);
- } else if (bound) {
- mBoundCount++;
- }
- mBoundState = state;
- mBoundStartTime = now;
- }
- }
-
- public void setExecuting(boolean executing, int memFactor, long now) {
- if (mActive <= 0) {
- throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
- }
- int state = executing ? memFactor : STATE_NOTHING;
- if (mExecState != state) {
- if (mExecState != STATE_NOTHING) {
- addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime);
- } else if (executing) {
- mExecCount++;
- }
- mExecState = state;
- mExecStartTime = now;
- }
- }
-
- long getStartDuration(int opType, int memFactor, long now) {
- switch (opType) {
- case SERVICE_STARTED:
- return getDuration(opType, mStartedState, mStartedStartTime, memFactor, now);
- case SERVICE_BOUND:
- return getDuration(opType, mBoundState, mBoundStartTime, memFactor, now);
- case SERVICE_EXEC:
- return getDuration(opType, mExecState, mExecStartTime, memFactor, now);
- default:
- throw new IllegalArgumentException("Bad opType: " + opType);
- }
- }
-
-
- private long getDuration(int opType, int curState, long startTime, int memFactor,
- long now) {
- int state = opType + (memFactor*SERVICE_COUNT);
- int idx = State.binarySearch(mDurationsTable, mDurationsTableSize, state);
- long time = idx >= 0 ? mState.getLong(mDurationsTable[idx], 0) : 0;
- if (curState == memFactor) {
- time += now - startTime;
- }
- return time;
- }
- }
-
- public static final class PackageState {
- final ArrayMap<String, ProcessState> mProcesses = new ArrayMap<String, ProcessState>();
- final ArrayMap<String, ServiceState> mServices = new ArrayMap<String, ServiceState>();
- final int mUid;
-
- public PackageState(int uid) {
- mUid = uid;
- }
- }
-
- static final class State {
- // Current version of the parcel format.
- private static final int PARCEL_VERSION = 9;
- // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
- private static final int MAGIC = 0x50535453;
-
- static final int FLAG_COMPLETE = 1<<0;
- static final int FLAG_SHUTDOWN = 1<<1;
- static final int FLAG_SYSPROPS = 1<<2;
-
- final File mBaseDir;
- final ProcessTracker mProcessTracker;
- AtomicFile mFile;
- String mReadError;
-
- long mTimePeriodStartClock;
- String mTimePeriodStartClockStr;
- long mTimePeriodStartRealtime;
- long mTimePeriodEndRealtime;
- String mRuntime;
- String mWebView;
- boolean mRunning;
- int mFlags;
-
- 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;
-
- static final int LONGS_SIZE = 4096;
- final ArrayList<long[]> mLongs = new ArrayList<long[]>();
- int mNextLong;
-
- int[] mAddLongTable;
- int mAddLongTableSize;
-
- final Object mPendingWriteLock = new Object();
- AtomicFile mPendingWriteFile;
- Parcel mPendingWrite;
- boolean mPendingWriteCommitted;
- long mLastWriteTime;
-
- State(File baseDir, ProcessTracker tracker) {
- mBaseDir = baseDir;
- reset();
- mProcessTracker = tracker;
- }
-
- State(String file) {
- mBaseDir = null;
- reset();
- mFile = new AtomicFile(new File(file));
- mProcessTracker = null;
- readLocked();
- }
-
- void reset() {
- if (DEBUG && mFile != null) Slog.d(TAG, "Resetting state of " + mFile.getBaseFile());
- resetCommon();
- mPackages.getMap().clear();
- mProcesses.getMap().clear();
- mMemFactor = STATE_NOTHING;
- mStartTime = 0;
- if (DEBUG && mFile != null) Slog.d(TAG, "State reset; now " + mFile.getBaseFile());
- }
-
- void resetSafely() {
- if (DEBUG && mFile != null) Slog.d(TAG, "Safely resetting state of " + mFile.getBaseFile());
- resetCommon();
- long now = SystemClock.uptimeMillis();
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- for (int ip=procMap.size()-1; ip>=0; ip--) {
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- for (int iu=uids.size()-1; iu>=0; iu--) {
- uids.valueAt(iu).resetSafely(now);
- }
- }
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- for (int ip=pkgMap.size()-1; ip>=0; ip--) {
- SparseArray<PackageState> uids = pkgMap.valueAt(ip);
- for (int iu=uids.size()-1; iu>=0; iu--) {
- PackageState pkgState = uids.valueAt(iu);
- for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
- pkgState.mProcesses.valueAt(iproc).resetSafely(now);
- }
- for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
- ServiceState ss = pkgState.mServices.valueAt(isvc);
- if (ss.isActive()) {
- pkgState.mServices.valueAt(isvc).resetSafely(now);
- } else {
- pkgState.mServices.removeAt(isvc);
- }
- }
- }
- }
- mStartTime = SystemClock.uptimeMillis();
- if (DEBUG && mFile != null) Slog.d(TAG, "State reset; now " + mFile.getBaseFile());
- }
-
- private void resetCommon() {
- mLastWriteTime = SystemClock.uptimeMillis();
- mTimePeriodStartClock = System.currentTimeMillis();
- buildTimePeriodStartClockStr();
- mTimePeriodStartRealtime = mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
- mLongs.clear();
- mLongs.add(new long[LONGS_SIZE]);
- mNextLong = 0;
- Arrays.fill(mMemFactorDurations, 0);
- mStartTime = 0;
- mReadError = null;
- mFlags = 0;
- evaluateSystemProperties(true);
- }
-
- public boolean evaluateSystemProperties(boolean update) {
- boolean changed = false;
- String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib",
- VMRuntime.getRuntime().vmLibrary());
- if (!Objects.equals(runtime, mRuntime)) {
- changed = true;
- if (update) {
- mRuntime = runtime;
- }
- }
- String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
- if (!Objects.equals(webview, mWebView)) {
- changed = true;
- if (update) {
- mWebView = webview;
- }
- }
- return changed;
- }
-
- private void buildTimePeriodStartClockStr() {
- mTimePeriodStartClockStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss",
- mTimePeriodStartClock).toString();
- if (mBaseDir != null) {
- mFile = new AtomicFile(new File(mBaseDir,
- STATE_FILE_PREFIX + mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
- }
- }
-
- static byte[] readFully(FileInputStream stream) throws java.io.IOException {
- int pos = 0;
- int avail = stream.available();
- byte[] data = new byte[avail];
- while (true) {
- int amt = stream.read(data, pos, data.length-pos);
- //Log.i("foo", "Read " + amt + " bytes at " + pos
- // + " of avail " + data.length);
- if (amt <= 0) {
- //Log.i("foo", "**** FINISHED READING: pos=" + pos
- // + " len=" + data.length);
- return data;
- }
- pos += amt;
- avail = stream.available();
- if (avail > data.length-pos) {
- byte[] newData = new byte[pos+avail];
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- }
- }
-
- boolean readLocked() {
- try {
- FileInputStream stream = mFile.openRead();
-
- byte[] raw = readFully(stream);
- Parcel in = Parcel.obtain();
- in.unmarshall(raw, 0, raw.length);
- in.setDataPosition(0);
- stream.close();
-
- readFromParcel(in);
- if (mReadError != null) {
- Slog.w(TAG, "Ignoring existing stats; " + mReadError);
- if (DEBUG) {
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- final int NPROC = procMap.size();
- for (int ip=0; ip<NPROC; ip++) {
- Slog.w(TAG, "Process: " + procMap.keyAt(ip));
- SparseArray<ProcessState> uids = procMap.valueAt(ip);
- final int NUID = uids.size();
- for (int iu=0; iu<NUID; iu++) {
- Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
- }
- }
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- final int NPKG = pkgMap.size();
- for (int ip=0; ip<NPKG; ip++) {
- Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
- SparseArray<PackageState> uids = pkgMap.valueAt(ip);
- final int NUID = uids.size();
- for (int iu=0; iu<NUID; iu++) {
- Slog.w(TAG, " Uid: " + uids.keyAt(iu));
- PackageState pkgState = uids.valueAt(iu);
- final int NPROCS = pkgState.mProcesses.size();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- Slog.w(TAG, " Process " + pkgState.mProcesses.keyAt(iproc)
- + ": " + pkgState.mProcesses.valueAt(iproc));
- }
- final int NSRVS = pkgState.mServices.size();
- for (int isvc=0; isvc<NSRVS; isvc++) {
- Slog.w(TAG, " Service " + pkgState.mServices.keyAt(isvc)
- + ": " + pkgState.mServices.valueAt(isvc));
- }
- }
- }
- }
- return false;
- }
- } catch (Throwable e) {
- mReadError = "caught exception: " + e;
- Slog.e(TAG, "Error reading process statistics", e);
- return false;
- }
- return true;
- }
-
- static final int[] BAD_TABLE = new int[0];
-
- private int[] readTableFromParcel(Parcel in, String name, String what) {
- final int size = in.readInt();
- if (size < 0) {
- Slog.w(TAG, "Ignoring existing stats; bad " + what + " table size: " + size);
- return BAD_TABLE;
- }
- if (size == 0) {
- return null;
- }
- final int[] table = new int[size];
- for (int i=0; i<size; i++) {
- table[i] = in.readInt();
- if (DEBUG) Slog.i(TAG, "Reading in " + name + " table #" + i + ": "
- + State.printLongOffset(table[i]));
- if (!validateLongOffset(table[i])) {
- Slog.w(TAG, "Ignoring existing stats; bad " + what + " table entry: "
- + State.printLongOffset(table[i]));
- return null;
- }
- }
- return table;
- }
-
- private void writeStateLocked(boolean sync, final boolean commit) {
- synchronized (mPendingWriteLock) {
- long now = SystemClock.uptimeMillis();
- if (mPendingWrite == null || !mPendingWriteCommitted) {
- mPendingWrite = Parcel.obtain();
- mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
- if (commit) {
- mFlags |= State.FLAG_COMPLETE;
- }
- writeToParcel(mPendingWrite);
- mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
- mPendingWriteCommitted = commit;
- }
- if (commit) {
- resetSafely();
- } else {
- mLastWriteTime = SystemClock.uptimeMillis();
- }
- Slog.i(TAG, "Prepared write state in " + (SystemClock.uptimeMillis()-now) + "ms");
- if (!sync) {
- BackgroundThread.getHandler().post(new Runnable() {
- @Override public void run() {
- performWriteState();
- }
- });
- return;
- }
- }
-
- performWriteState();
- }
-
- void performWriteState() {
- if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
- Parcel data;
- AtomicFile file;
- synchronized (mPendingWriteLock) {
- data = mPendingWrite;
- file = mPendingWriteFile;
- mPendingWriteCommitted = false;
- if (data == null) {
- return;
- }
- mPendingWrite = null;
- mPendingWriteFile = null;
- if (mProcessTracker != null) {
- mProcessTracker.mWriteLock.lock();
- }
- }
-
- FileOutputStream stream = null;
- try {
- stream = file.startWrite();
- stream.write(data.marshall());
- stream.flush();
- file.finishWrite(stream);
- if (DEBUG) Slog.d(TAG, "Write completed successfully!");
- } catch (IOException e) {
- Slog.w(TAG, "Error writing process statistics", e);
- file.failWrite(stream);
- } finally {
- data.recycle();
- if (mProcessTracker != null) {
- mProcessTracker.trimHistoricStatesWriteLocked();
- mProcessTracker.mWriteLock.unlock();
- }
- }
-
- }
-
- void writeToParcel(Parcel out) {
- long now = SystemClock.uptimeMillis();
- out.writeInt(MAGIC);
- out.writeInt(PARCEL_VERSION);
- out.writeInt(STATE_COUNT);
- out.writeInt(ADJ_COUNT);
- out.writeInt(PSS_COUNT);
- out.writeInt(LONGS_SIZE);
-
- out.writeLong(mTimePeriodStartClock);
- out.writeLong(mTimePeriodStartRealtime);
- out.writeLong(mTimePeriodEndRealtime);
- out.writeString(mRuntime);
- out.writeString(mWebView);
- out.writeInt(mFlags);
-
- out.writeInt(mLongs.size());
- out.writeInt(mNextLong);
- for (int i=0; i<(mLongs.size()-1); i++) {
- out.writeLongArray(mLongs.get(i));
- }
- long[] lastLongs = mLongs.get(mLongs.size()-1);
- for (int i=0; i<mNextLong; i++) {
- out.writeLong(lastLongs[i]);
- if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]);
- }
-
- if (mMemFactor != STATE_NOTHING) {
- mMemFactorDurations[mMemFactor] += now - mStartTime;
- mStartTime = now;
- }
- out.writeLongArray(mMemFactorDurations);
-
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- final int NPROC = procMap.size();
- out.writeInt(NPROC);
- for (int ip=0; ip<NPROC; ip++) {
- out.writeString(procMap.keyAt(ip));
- 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));
- ProcessState proc = uids.valueAt(iu);
- out.writeString(proc.mPackage);
- proc.writeToParcel(out, now);
- }
- }
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- final int NPKG = pkgMap.size();
- out.writeInt(NPKG);
- for (int ip=0; ip<NPKG; ip++) {
- out.writeString(pkgMap.keyAt(ip));
- SparseArray<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));
- PackageState pkgState = uids.valueAt(iu);
- final int NPROCS = pkgState.mProcesses.size();
- out.writeInt(NPROCS);
- for (int iproc=0; iproc<NPROCS; iproc++) {
- out.writeString(pkgState.mProcesses.keyAt(iproc));
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- if (proc.mCommonProcess == 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));
- ServiceState svc = pkgState.mServices.valueAt(isvc);
- svc.writeToParcel(out, now);
- }
- }
- }
- }
-
- private boolean readCheckedInt(Parcel in, int val, String what) {
- int got;
- if ((got=in.readInt()) != val) {
- mReadError = "bad " + what + ": " + got;
- return false;
- }
- return true;
- }
-
- private 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 && version != 6) {
- 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, LONGS_SIZE, "longs size")) {
- return;
- }
-
- mTimePeriodStartClock = in.readLong();
- buildTimePeriodStartClockStr();
- mTimePeriodStartRealtime = in.readLong();
- mTimePeriodEndRealtime = in.readLong();
- if (version == PARCEL_VERSION) {
- mRuntime = in.readString();
- mWebView = in.readString();
- }
- mFlags = in.readInt();
-
- final int NLONGS = in.readInt();
- final int NEXTLONG = in.readInt();
- mLongs.clear();
- for (int i=0; i<(NLONGS-1); i++) {
- while (i >= mLongs.size()) {
- mLongs.add(new long[LONGS_SIZE]);
- }
- in.readLongArray(mLongs.get(i));
- }
- long[] longs = new long[LONGS_SIZE];
- mNextLong = NEXTLONG;
- for (int i=0; i<NEXTLONG; i++) {
- longs[i] = in.readLong();
- if (DEBUG) Slog.d(TAG, "Reading last long #" + i + ": " + longs[i]);
- }
- mLongs.add(longs);
-
- in.readLongArray(mMemFactorDurations);
-
- int NPROC = in.readInt();
- if (NPROC < 0) {
- mReadError = "bad process count: " + NPROC;
- return;
- }
- while (NPROC > 0) {
- NPROC--;
- String procName = in.readString();
- 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--;
- int uid = in.readInt();
- if (uid < 0) {
- mReadError = "bad uid: " + uid;
- return;
- }
- String pkgName = in.readString();
- if (pkgName == null) {
- mReadError = "bad process package name";
- return;
- }
- ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
- if (proc != null) {
- if (!proc.readFromParcel(in, false)) {
- return;
- }
- } else {
- proc = new ProcessState(this, pkgName, uid, procName);
- if (!proc.readFromParcel(in, true)) {
- return;
- }
- }
- if (DEBUG) Slog.d(TAG, "Adding process: " + procName + " " + uid + " " + proc);
- mProcesses.put(procName, uid, proc);
- }
- }
-
- if (DEBUG) 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--;
- String pkgName = in.readString();
- 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--;
- int uid = in.readInt();
- if (uid < 0) {
- mReadError = "bad uid: " + uid;
- return;
- }
- PackageState pkgState = new PackageState(uid);
- mPackages.put(pkgName, uid, pkgState);
- int NPROCS = in.readInt();
- if (NPROCS < 0) {
- mReadError = "bad package process count: " + NPROCS;
- return;
- }
- while (NPROCS > 0) {
- NPROCS--;
- String procName = in.readString();
- if (procName == null) {
- mReadError = "bad package process name";
- return;
- }
- int hasProc = in.readInt();
- if (DEBUG) Slog.d(TAG, "Reading package " + pkgName + " " + uid
- + " process " + procName + " hasProc=" + hasProc);
- ProcessState commonProc = mProcesses.get(procName, uid);
- if (DEBUG) 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, procName, 0);
- if (!proc.readFromParcel(in, true)) {
- return;
- }
- }
- if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " process: "
- + procName + " " + uid + " " + proc);
- pkgState.mProcesses.put(procName, proc);
- } else {
- if (DEBUG) 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;
- }
- ServiceState serv = hadData ? pkgState.mServices.get(serviceName) : null;
- if (serv == null) {
- serv = new ServiceState(this, pkgName, null);
- }
- if (!serv.readFromParcel(in)) {
- return;
- }
- if (DEBUG) Slog.d(TAG, "Adding package " + pkgName + " service: "
- + serviceName + " " + uid + " " + serv);
- pkgState.mServices.put(serviceName, serv);
- }
- }
- }
-
- if (DEBUG) Slog.d(TAG, "Successfully read procstats!");
- }
-
- int addLongData(int index, int type, int num) {
- int tableLen = mAddLongTable != null ? mAddLongTable.length : 0;
- if (mAddLongTableSize >= tableLen) {
- int newSize = ArrayUtils.idealIntArraySize(tableLen + 1);
- int[] newTable = new int[newSize];
- if (tableLen > 0) {
- System.arraycopy(mAddLongTable, 0, newTable, 0, tableLen);
- }
- mAddLongTable = newTable;
- }
- if (mAddLongTableSize > 0 && mAddLongTableSize - index != 0) {
- System.arraycopy(mAddLongTable, index, mAddLongTable, index + 1,
- mAddLongTableSize - index);
- }
- int off = allocLongData(num);
- mAddLongTable[index] = type | off;
- mAddLongTableSize++;
- return off;
- }
-
- int allocLongData(int num) {
- int whichLongs = mLongs.size()-1;
- long[] longs = mLongs.get(whichLongs);
- if (mNextLong + num > longs.length) {
- longs = new long[LONGS_SIZE];
- mLongs.add(longs);
- whichLongs++;
- mNextLong = 0;
- }
- int off = (whichLongs<<OFFSET_ARRAY_SHIFT) | (mNextLong<<OFFSET_INDEX_SHIFT);
- mNextLong += num;
- return off;
- }
-
- boolean validateLongOffset(int off) {
- int arr = (off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK;
- if (arr >= mLongs.size()) {
- return false;
- }
- int idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
- if (idx >= LONGS_SIZE) {
- return false;
- }
- if (DEBUG) Slog.d(TAG, "Validated long " + printLongOffset(off)
- + ": " + getLong(off, 0));
- return true;
- }
-
- static String printLongOffset(int off) {
- StringBuilder sb = new StringBuilder(16);
- sb.append("a"); sb.append((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- sb.append("i"); sb.append((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK);
- sb.append("t"); sb.append((off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK);
- return sb.toString();
- }
-
- void setLong(int off, int index, long value) {
- long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)] = value;
- }
-
- long getLong(int off, int index) {
- long[] longs = mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
- return longs[index + ((off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK)];
- }
-
- static int binarySearch(int[] array, int size, int value) {
- int lo = 0;
- int hi = size - 1;
-
- while (lo <= hi) {
- int mid = (lo + hi) >>> 1;
- int midVal = (array[mid] >> OFFSET_TYPE_SHIFT) & OFFSET_TYPE_MASK;
-
- if (midVal < value) {
- lo = mid + 1;
- } else if (midVal > value) {
- hi = mid - 1;
- } else {
- return mid; // value found
- }
- }
- return ~lo; // value not present
- }
-
- 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;
- }
-
- 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.mName, 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;
- }
-
- void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) {
- long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
- mStartTime, now);
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- boolean printedHeader = false;
- 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 pkgState = uids.valueAt(iu);
- final int NPROCS = pkgState.mProcesses.size();
- final int NSRVS = pkgState.mServices.size();
- 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 (dumpAll) {
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- pw.print(" Process ");
- pw.print(pkgState.mProcesses.keyAt(iproc));
- pw.print(" (");
- pw.print(proc.mDurationsTableSize);
- pw.print(" entries)");
- pw.println(":");
- dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES);
- if (dumpAll) {
- pw.print(" mNumStartedServices=");
- pw.println(proc.mNumStartedServices);
- }
- }
- } else {
- ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- procs.add(pkgState.mProcesses.valueAt(iproc));
- }
- dumpProcessSummaryLocked(pw, " ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- NON_CACHED_PROC_STATES, now, totalTime);
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- if (dumpAll) {
- pw.print(" Service ");
- } else {
- pw.print(" * ");
- }
- pw.print(pkgState.mServices.keyAt(isvc));
- pw.println(":");
- ServiceState svc = pkgState.mServices.valueAt(isvc);
- dumpServiceStats(pw, " ", " ", " ", "Started", svc,
- svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
- svc.mStartedStartTime, now, totalTime, dumpAll);
- dumpServiceStats(pw, " ", " ", " ", "Bound", svc,
- svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
- svc.mBoundStartTime, now, totalTime, dumpAll);
- dumpServiceStats(pw, " ", " ", " ", "Executing", svc,
- svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
- svc.mExecStartTime, now, totalTime, dumpAll);
- }
- }
- }
-
- if (reqPackage == null) {
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- printedHeader = false;
- 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 proc = uids.valueAt(iu);
- if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
- && proc.mPssTableSize == 0) {
- continue;
- }
- if (!printedHeader) {
- pw.println("Process Stats:");
- printedHeader = true;
- }
- pw.print(" * "); pw.print(procName); pw.print(" / ");
- UserHandle.formatUid(pw, uid);
- pw.print(" ("); pw.print(proc.mDurationsTableSize);
- pw.print(" entries)"); pw.println(":");
- dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES, now);
- dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- ALL_PROC_STATES);
- }
- }
-
- pw.println();
- pw.println("Summary:");
- dumpSummaryLocked(pw, reqPackage, now);
- } else {
- pw.println();
- dumpTotalsLocked(pw, now);
- }
-
- if (dumpAll) {
- pw.println();
- pw.println("Internal state:");
- pw.print(" mFile="); pw.println(mFile.getBaseFile());
- pw.print(" Num long arrays: "); pw.println(mLongs.size());
- pw.print(" Next long entry: "); pw.println(mNextLong);
- pw.print(" mRunning="); pw.println(mRunning);
- }
- }
-
- static long dumpSingleServiceTime(PrintWriter pw, String prefix, ServiceState service,
- int serviceType, int curState, long curStartTime, 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++) {
- int state = imem+iscreen;
- long time = service.getDuration(serviceType, curState, curStartTime,
- state, now);
- String running = "";
- if (curState == state) {
- time += now - curStartTime;
- if (pw != null) {
- running = " (running)";
- }
- }
- if (time != 0) {
- if (pw != null) {
- pw.print(prefix);
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
- printedMem = imem;
- TimeUtils.formatDuration(time, pw); pw.println(running);
- }
- totalTime += time;
- }
- }
- }
- if (totalTime != 0 && pw != null) {
- pw.print(prefix);
- printScreenLabel(pw, STATE_NOTHING);
- pw.print("TOTAL: ");
- TimeUtils.formatDuration(totalTime, pw);
- pw.println();
- }
- return totalTime;
- }
-
- void dumpServiceStats(PrintWriter pw, String prefix, String prefixInner,
- String headerPrefix, String header, ServiceState service,
- int count, int serviceType, int state, long startTime, long now, long totalTime,
- boolean dumpAll) {
- if (count != 0) {
- if (dumpAll) {
- pw.print(prefix); pw.print(header);
- pw.print(" op count "); pw.print(count); pw.println(":");
- dumpSingleServiceTime(pw, prefixInner, service, serviceType, state, startTime,
- now);
- } else {
- long myTime = dumpSingleServiceTime(null, null, service, serviceType, state,
- startTime, now);
- pw.print(prefix); pw.print(headerPrefix); pw.print(header);
- pw.print(" count "); pw.print(count);
- pw.print(" / time ");
- printPercent(pw, (double)myTime/(double)totalTime);
- pw.println();
- }
- }
- }
-
- void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
- long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
- mStartTime, now);
- dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- NON_CACHED_PROC_STATES, now, totalTime, reqPackage);
- pw.println();
- dumpTotalsLocked(pw, now);
- }
-
- void dumpTotalsLocked(PrintWriter pw, long now) {
- pw.println("Run time Stats:");
- dumpSingleTime(pw, " ", mMemFactorDurations, mMemFactor, mStartTime, now);
- pw.println();
- pw.print(" Start time: ");
- pw.print(DateFormat.format("yyyy-MM-dd HH:mm:ss", mTimePeriodStartClock));
- 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)");
- }
- pw.print(' ');
- pw.print(mRuntime);
- pw.print(' ');
- pw.print(mWebView);
- pw.println();
- }
-
- void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
- int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime,
- String reqPackage) {
- ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
- procStates, now, reqPackage);
- if (procs.size() > 0) {
- if (header != null) {
- pw.println();
- pw.println(header);
- }
- dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates, procStates,
- now, totalTime);
- }
- }
-
- ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
- int[] procStates, long now, String reqPackage) {
- ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
- ArrayMap<String, SparseArray<PackageState>> pkgMap = 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++) {
- ProcessState proc = state.mProcesses.valueAt(iproc);
- foundProcs.add(proc.mCommonProcess);
- }
- }
- }
- 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) {
- if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
- return -1;
- } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
- return 1;
- }
- return 0;
- }
- });
- return outProcs;
- }
-
- String collapseString(String pkgName, String itemName) {
- if (itemName.startsWith(pkgName)) {
- final int ITEMLEN = itemName.length();
- final int PKGLEN = pkgName.length();
- if (ITEMLEN == PKGLEN) {
- return "";
- } else if (ITEMLEN >= PKGLEN) {
- if (itemName.charAt(PKGLEN) == '.') {
- return itemName.substring(PKGLEN);
- }
- }
- }
- return itemName;
- }
-
- void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
- final long now = SystemClock.uptimeMillis();
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- pw.println("vers,3");
- 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");
- }
- pw.println();
- pw.print("config,"); pw.print(mRuntime); pw.print(','); pw.println(mWebView);
- 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 pkgState = uids.valueAt(iu);
- final int NPROCS = pkgState.mProcesses.size();
- final int NSRVS = pkgState.mServices.size();
- for (int iproc=0; iproc<NPROCS; iproc++) {
- ProcessState proc = pkgState.mProcesses.valueAt(iproc);
- pw.print("pkgproc,");
- pw.print(pkgName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
- dumpAllProcessStateCheckin(pw, proc, now);
- pw.println();
- if (proc.mPssTableSize > 0) {
- pw.print("pkgpss,");
- pw.print(pkgName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
- dumpAllProcessPssCheckin(pw, proc);
- pw.println();
- }
- if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0) {
- pw.print("pkgkills,");
- pw.print(pkgName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(collapseString(pkgName, pkgState.mProcesses.keyAt(iproc)));
- pw.print(",");
- pw.print(proc.mNumExcessiveWake);
- pw.print(",");
- pw.print(proc.mNumExcessiveCpu);
- pw.println();
- }
- }
- for (int isvc=0; isvc<NSRVS; isvc++) {
- String serviceName = collapseString(pkgName,
- pkgState.mServices.keyAt(isvc));
- ServiceState svc = pkgState.mServices.valueAt(isvc);
- dumpServiceTimeCheckin(pw, "pkgsvc-start", pkgName, uid, serviceName,
- svc, ServiceState.SERVICE_STARTED, svc.mStartedCount,
- svc.mStartedState, svc.mStartedStartTime, now);
- dumpServiceTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, serviceName,
- svc, ServiceState.SERVICE_BOUND, svc.mBoundCount,
- svc.mBoundState, svc.mBoundStartTime, now);
- dumpServiceTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, serviceName,
- svc, ServiceState.SERVICE_EXEC, svc.mExecCount,
- svc.mExecState, svc.mExecStartTime, now);
- }
- }
- }
-
- 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++) {
- int uid = uids.keyAt(iu);
- ProcessState procState = uids.valueAt(iu);
- if (procState.mDurationsTableSize > 0) {
- pw.print("proc,");
- pw.print(procName);
- pw.print(",");
- pw.print(uid);
- dumpAllProcessStateCheckin(pw, procState, now);
- pw.println();
- }
- if (procState.mPssTableSize > 0) {
- pw.print("pss,");
- pw.print(procName);
- pw.print(",");
- pw.print(uid);
- dumpAllProcessPssCheckin(pw, procState);
- pw.println();
- }
- if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0) {
- pw.print("kills,");
- pw.print(procName);
- pw.print(",");
- pw.print(uid);
- pw.print(",");
- pw.print(procState.mNumExcessiveWake);
- pw.print(",");
- pw.print(procState.mNumExcessiveCpu);
- pw.println();
- }
- }
- }
- pw.print("total");
- dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
- mStartTime, now);
- pw.println();
- }
- }
-
- public ProcessTracker(Object lock, File file) {
- mLock = lock;
- mBaseDir = file;
- mBaseDir.mkdirs();
- mState = new State(mBaseDir, this);
- mState.mRunning = true;
- SystemProperties.addChangeCallback(new Runnable() {
- @Override public void run() {
- synchronized (mLock) {
- if (mState.evaluateSystemProperties(false)) {
- mState.mFlags |= State.FLAG_SYSPROPS;
- mState.writeStateLocked(true, true);
- mState.evaluateSystemProperties(true);
- }
- }
- }
- });
- }
-
- public ProcessState getProcessStateLocked(String packageName, int uid, String processName) {
- return mState.getProcessStateLocked(packageName, uid, processName);
- }
-
- public ServiceState getServiceStateLocked(String packageName, int uid,
- String processName, String className) {
- final PackageState as = mState.getPackageStateLocked(packageName, uid);
- ServiceState ss = as.mServices.get(className);
- if (ss != null) {
- ss.makeActive();
- return ss;
- }
- final ProcessState ps = mState.getProcessStateLocked(packageName, uid, processName);
- ss = new ServiceState(mState, packageName, ps);
- as.mServices.put(className, ss);
- return ss;
- }
-
- public boolean isMemFactorLowered() {
- return mMemFactorLowered;
- }
-
- public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
- mMemFactorLowered = memFactor < mLastMemOnlyState;
- mLastMemOnlyState = memFactor;
- 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<String, SparseArray<PackageState>> pmap = mState.mPackages.getMap();
- for (int i=0; i<pmap.size(); i++) {
- SparseArray<PackageState> uids = pmap.valueAt(i);
- for (int j=0; j<uids.size(); j++) {
- PackageState pkg = uids.valueAt(j);
- ArrayMap<String, ServiceState> services = pkg.mServices;
- for (int k=0; k<services.size(); k++) {
- ServiceState service = services.valueAt(k);
- if (service.isActive()) {
- if (service.mStartedState != STATE_NOTHING) {
- service.setStarted(true, memFactor, now);
- }
- if (service.mBoundState != STATE_NOTHING) {
- service.setBound(true, memFactor, now);
- }
- if (service.mExecState != STATE_NOTHING) {
- service.setExecuting(true, memFactor, now);
- }
- }
- }
- }
- }
- return true;
- }
- return false;
- }
-
- public int getMemFactorLocked() {
- return mState.mMemFactor != STATE_NOTHING ? mState.mMemFactor : 0;
- }
-
- public void readLocked() {
- mState.readLocked();
- }
-
- public boolean shouldWriteNowLocked(long now) {
- if (now > (mState.mLastWriteTime+WRITE_PERIOD)) {
- if (SystemClock.elapsedRealtime() > (mState.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
- mCommitPending = true;
- }
- return true;
- }
- return false;
- }
-
- public void shutdownLocked() {
- Slog.w(TAG, "Writing process stats before shutdown...");
- mState.mFlags |= State.FLAG_SHUTDOWN;
- writeStateSyncLocked();
- mShuttingDown = true;
- }
-
- public void writeStateAsyncLocked() {
- writeStateLocked(false);
- }
-
- public void writeStateSyncLocked() {
- writeStateLocked(true);
- }
-
- private void writeStateLocked(boolean sync) {
- if (mShuttingDown) {
- return;
- }
- boolean commitPending = mCommitPending;
- mCommitPending = false;
- mState.writeStateLocked(sync, commitPending);
- }
-
- private ArrayList<String> getCommittedFiles(int minNum, boolean inclAll) {
- File[] files = mBaseDir.listFiles();
- if (files == null || files.length <= minNum) {
- return null;
- }
- ArrayList<String> filesArray = new ArrayList<String>(files.length);
- String currentFile = mState.mFile.getBaseFile().getPath();
- if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
- for (int i=0; i<files.length; i++) {
- File file = files[i];
- String fileStr = file.getPath();
- if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
- if (!inclAll && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
- if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
- continue;
- }
- if (fileStr.equals(currentFile)) {
- if (DEBUG) Slog.d(TAG, "Skipping: current stats");
- continue;
- }
- filesArray.add(fileStr);
- }
- Collections.sort(filesArray);
- return filesArray;
- }
-
- public void trimHistoricStatesWriteLocked() {
- ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, true);
- if (filesArray == null) {
- return;
- }
- while (filesArray.size() > MAX_HISTORIC_STATES) {
- String file = filesArray.remove(0);
- Slog.i(TAG, "Pruning old procstats: " + file);
- (new File(file)).delete();
- }
- }
-
- static private void printScreenLabel(PrintWriter pw, int offset) {
- switch (offset) {
- case ADJ_NOTHING:
- pw.print(" ");
- break;
- case ADJ_SCREEN_OFF:
- pw.print("Screen Off / ");
- break;
- case ADJ_SCREEN_ON:
- pw.print("Screen On / ");
- break;
- default:
- pw.print("?????????? / ");
- break;
- }
- }
-
- 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:
- pw.print(" ");
- break;
- case ADJ_MEM_FACTOR_NORMAL:
- pw.print("Norm / ");
- break;
- case ADJ_MEM_FACTOR_MODERATE:
- pw.print("Mod / ");
- break;
- case ADJ_MEM_FACTOR_LOW:
- pw.print("Low / ");
- break;
- case ADJ_MEM_FACTOR_CRITICAL:
- pw.print("Crit / ");
- break;
- default:
- pw.print("???? / ");
- break;
- }
- }
-
- 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 long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
- int curState, long curStartTime, 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++) {
- int state = imem+iscreen;
- long time = durations[state];
- String running = "";
- if (curState == state) {
- time += now - curStartTime;
- if (pw != null) {
- running = " (running)";
- }
- }
- if (time != 0) {
- if (pw != null) {
- pw.print(prefix);
- printScreenLabel(pw, printedScreen != iscreen
- ? iscreen : STATE_NOTHING);
- printedScreen = iscreen;
- printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING);
- printedMem = imem;
- TimeUtils.formatDuration(time, pw); pw.println(running);
- }
- totalTime += time;
- }
- }
- }
- if (totalTime != 0 && pw != null) {
- pw.print(prefix);
- printScreenLabel(pw, STATE_NOTHING);
- pw.print("TOTAL: ");
- TimeUtils.formatDuration(totalTime, pw);
- pw.println();
- }
- return totalTime;
- }
-
- static void dumpAdjTimesCheckin(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;
- }
- if (time != 0) {
- printAdjTagAndValue(pw, state, time);
- }
- }
- }
- }
-
- static void dumpServiceTimeCheckin(PrintWriter pw, String label, String packageName,
- int uid, String serviceName, ServiceState svc, int serviceType, int opCount,
- 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(",");
- pw.print(opCount);
- boolean didCurState = false;
- for (int i=0; i<svc.mDurationsTableSize; i++) {
- int off = svc.mDurationsTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int memFactor = type / ServiceState.SERVICE_COUNT;
- type %= ServiceState.SERVICE_COUNT;
- if (type != serviceType) {
- continue;
- }
- long time = svc.mState.getLong(off, 0);
- if (curState == memFactor) {
- didCurState = true;
- time += now - curStartTime;
- }
- printAdjTagAndValue(pw, memFactor, time);
- }
- if (!didCurState && curState != STATE_NOTHING) {
- printAdjTagAndValue(pw, curState, now - curStartTime);
- }
- pw.println();
- }
-
- static final class ProcessDataCollection {
- final int[] screenStates;
- final int[] memStates;
- final int[] procStates;
-
- long totalTime;
- long numPss;
- long minPss;
- long avgPss;
- long maxPss;
- long minUss;
- long avgUss;
- long maxUss;
-
- ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
- screenStates = _screenStates;
- memStates = _memStates;
- procStates = _procStates;
- }
-
- void print(PrintWriter pw, long overallTime, boolean full) {
- printPercent(pw, (double) totalTime / (double) overallTime);
- if (numPss > 0) {
- pw.print(" (");
- printSizeValue(pw, minPss * 1024);
- pw.print("-");
- printSizeValue(pw, avgPss * 1024);
- pw.print("-");
- printSizeValue(pw, maxPss * 1024);
- pw.print("/");
- printSizeValue(pw, minUss * 1024);
- pw.print("-");
- printSizeValue(pw, avgUss * 1024);
- pw.print("-");
- printSizeValue(pw, maxUss * 1024);
- if (full) {
- pw.print(" over ");
- pw.print(numPss);
- }
- pw.print(")");
- }
- }
- }
-
- static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
- data.totalTime = 0;
- data.numPss = data.minPss = data.avgPss = data.maxPss =
- data.minUss = data.avgUss = data.maxUss = 0;
- for (int is=0; is<data.screenStates.length; is++) {
- for (int im=0; im<data.memStates.length; im++) {
- for (int ip=0; ip<data.procStates.length; ip++) {
- int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
- + data.procStates[ip];
- data.totalTime += proc.getDuration(bucket, now);
- long samples = proc.getPssSampleCount(bucket);
- if (samples > 0) {
- long minPss = proc.getPssMinimum(bucket);
- long avgPss = proc.getPssAverage(bucket);
- long maxPss = proc.getPssMaximum(bucket);
- long minUss = proc.getPssUssMinimum(bucket);
- long avgUss = proc.getPssUssAverage(bucket);
- long maxUss = proc.getPssUssMaximum(bucket);
- if (data.numPss == 0) {
- data.minPss = minPss;
- data.avgPss = avgPss;
- data.maxPss = maxPss;
- data.minUss = minUss;
- data.avgUss = avgUss;
- data.maxUss = maxUss;
- } else {
- if (minPss < data.minPss) {
- data.minPss = minPss;
- }
- data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
- + (avgPss*(double)samples)) / (data.numPss+samples) );
- if (maxPss > data.maxPss) {
- data.maxPss = maxPss;
- }
- if (minUss < data.minUss) {
- data.minUss = minUss;
- }
- data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
- + (avgUss*(double)samples)) / (data.numPss+samples) );
- if (maxUss > data.maxUss) {
- data.maxUss = maxUss;
- }
- }
- data.numPss += samples;
- }
- }
- }
- }
- }
-
- static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
- int[] procStates, long now) {
- long totalTime = 0;
- /*
- for (int i=0; i<proc.mDurationsTableSize; i++) {
- int val = proc.mDurationsTable[i];
- totalTime += proc.mState.getLong(val, 0);
- if ((val&0xff) == proc.mCurState) {
- totalTime += now - proc.mStartTime;
- }
- }
- */
- for (int is=0; is<screenStates.length; is++) {
- for (int im=0; im<memStates.length; im++) {
- for (int ip=0; ip<procStates.length; ip++) {
- int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
- + procStates[ip];
- totalTime += proc.getDuration(bucket, now);
- }
- }
- }
- proc.mTmpTotalTime = totalTime;
- return totalTime;
- }
-
- static 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<screenStates.length; is++) {
- int printedMem = -1;
- for (int im=0; im<memStates.length; im++) {
- for (int ip=0; ip<procStates.length; ip++) {
- final int iscreen = screenStates[is];
- final int imem = memStates[im];
- final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
- long time = proc.getDuration(bucket, now);
- String running = "";
- if (proc.mCurState == bucket) {
- running = " (running)";
- }
- if (time != 0) {
- pw.print(prefix);
- if (screenStates.length > 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();
- }
- }
-
- static void dumpProcessPss(PrintWriter pw, String prefix, ProcessState proc, int[] screenStates,
- int[] memStates, int[] procStates) {
- boolean printedHeader = false;
- int printedScreen = -1;
- for (int is=0; is<screenStates.length; is++) {
- int printedMem = -1;
- for (int im=0; im<memStates.length; im++) {
- for (int ip=0; ip<procStates.length; ip++) {
- final int iscreen = screenStates[is];
- final int imem = memStates[im];
- final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
- long count = proc.getPssSampleCount(bucket);
- if (count > 0) {
- if (!printedHeader) {
- pw.print(prefix);
- pw.print("PSS/USS (");
- pw.print(proc.mPssTableSize);
- pw.println(" entries):");
- printedHeader = true;
- }
- pw.print(prefix);
- pw.print(" ");
- if (screenStates.length > 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(": ");
- pw.print(count);
- pw.print(" samples ");
- printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
- pw.print(" ");
- printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
- pw.print(" ");
- printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
- pw.print(" / ");
- printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
- pw.print(" ");
- printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
- pw.print(" ");
- printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
- pw.println();
- }
- }
- }
- }
- if (proc.mNumExcessiveWake != 0) {
- pw.print(prefix); pw.print("Killed for excessive wake locks: ");
- pw.print(proc.mNumExcessiveWake); pw.println(" times");
- }
- if (proc.mNumExcessiveCpu != 0) {
- pw.print(prefix); pw.print("Killed for excessive CPU use: ");
- pw.print(proc.mNumExcessiveCpu); pw.println(" times");
- }
- }
-
- static 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]]);
- }
- }
- }
- }
- }
-
- static 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.getDuration(bucket, now);
- }
- }
- }
- pw.print(CSV_SEP);
- pw.print(totalTime);
- }
- }
- }
- }
-
- static 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.mName);
- pw.print(" / ");
- UserHandle.formatUid(pw, proc.mUid);
- pw.print(" (");
- pw.print(proc.mDurationsTableSize);
- pw.print(" entries)");
- pw.println(":");
- dumpProcessState(pw, innerPrefix, proc, screenStates, memStates, procStates, now);
- if (proc.mPssTableSize > 0) {
- dumpProcessPss(pw, innerPrefix, proc, screenStates, memStates, procStates);
- }
- }
- }
-
- static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
- String label, int[] screenStates, int[] memStates, int[] procStates,
- long now, long totalTime, boolean full) {
- ProcessDataCollection totals = new ProcessDataCollection(screenStates,
- memStates, procStates);
- computeProcessData(proc, totals, now);
- if (totals.totalTime != 0 || totals.numPss != 0) {
- if (prefix != null) {
- pw.print(prefix);
- }
- if (label != null) {
- pw.print(label);
- }
- totals.print(pw, totalTime, full);
- if (prefix != null) {
- pw.println();
- }
- }
- }
-
- static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
- ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
- long now, long totalTime) {
- for (int i=procs.size()-1; i>=0; i--) {
- ProcessState proc = procs.get(i);
- pw.print(prefix);
- pw.print("* ");
- pw.print(proc.mName);
- pw.print(" / ");
- UserHandle.formatUid(pw, proc.mUid);
- pw.println(":");
- dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates,
- procStates, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates,
- new int[] { STATE_PERSISTENT }, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates,
- new int[] {STATE_TOP}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Imp Fg: ", screenStates, memStates,
- new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Imp Bg: ", screenStates, memStates,
- new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates,
- new int[] {STATE_BACKUP}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Heavy Wgt: ", screenStates, memStates,
- new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates,
- new int[] {STATE_SERVICE}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Service Rs: ", screenStates, memStates,
- new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Receiver: ", screenStates, memStates,
- new int[] {STATE_RECEIVER}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Home: ", screenStates, memStates,
- new int[] {STATE_HOME}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " (Last Act): ", screenStates, memStates,
- new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates,
- new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
- STATE_CACHED_EMPTY}, now, totalTime, true);
- }
- }
-
- static void printPercent(PrintWriter pw, double fraction) {
- fraction *= 100;
- if (fraction < 1) {
- pw.print(String.format("%.2f", fraction));
- } else if (fraction < 10) {
- pw.print(String.format("%.1f", fraction));
- } else {
- pw.print(String.format("%.0f", fraction));
- }
- pw.print("%");
- }
-
- static void printSizeValue(PrintWriter pw, long number) {
- float result = number;
- String suffix = "";
- if (result > 900) {
- suffix = "KB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "MB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "GB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "TB";
- result = result / 1024;
- }
- if (result > 900) {
- suffix = "PB";
- result = result / 1024;
- }
- String value;
- if (result < 1) {
- value = String.format("%.2f", result);
- } else if (result < 10) {
- value = String.format("%.1f", result);
- } else if (result < 100) {
- value = String.format("%.0f", result);
- } else {
- value = String.format("%.0f", result);
- }
- pw.print(value);
- pw.print(suffix);
- }
-
- static 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();
- }
- }
-
- boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
- boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
- boolean sepProcStates, int[] procStates, long now, String reqPackage) {
- ArrayList<ProcessState> procs = mState.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;
- }
-
- static int printArrayEntry(PrintWriter pw, String[] array, int value, int mod) {
- int index = value/mod;
- if (index >= 0 && index < array.length) {
- pw.print(array[index]);
- } else {
- pw.print('?');
- }
- return value - index*mod;
- }
-
- static void printProcStateTag(PrintWriter pw, int state) {
- state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD*STATE_COUNT);
- state = printArrayEntry(pw, ADJ_MEM_TAGS, state, STATE_COUNT);
- printArrayEntry(pw, STATE_TAGS, state, 1);
- }
-
- static void printAdjTag(PrintWriter pw, int state) {
- state = printArrayEntry(pw, ADJ_SCREEN_TAGS, state, ADJ_SCREEN_MOD);
- printArrayEntry(pw, ADJ_MEM_TAGS, state, 1);
- }
-
- static void printProcStateTagAndValue(PrintWriter pw, int state, long value) {
- pw.print(',');
- printProcStateTag(pw, state);
- pw.print(':');
- pw.print(value);
- }
-
- static void printAdjTagAndValue(PrintWriter pw, int state, long value) {
- pw.print(',');
- printAdjTag(pw, state);
- pw.print(':');
- pw.print(value);
- }
-
- static void dumpAllProcessStateCheckin(PrintWriter pw, ProcessState proc, long now) {
- boolean didCurState = false;
- for (int i=0; i<proc.mDurationsTableSize; i++) {
- int off = proc.mDurationsTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long time = proc.mState.getLong(off, 0);
- if (proc.mCurState == type) {
- didCurState = true;
- time += now - proc.mStartTime;
- }
- printProcStateTagAndValue(pw, type, time);
- }
- if (!didCurState && proc.mCurState != STATE_NOTHING) {
- printProcStateTagAndValue(pw, proc.mCurState, now - proc.mStartTime);
- }
- }
-
- static void dumpAllProcessPssCheckin(PrintWriter pw, ProcessState proc) {
- for (int i=0; i<proc.mPssTableSize; i++) {
- int off = proc.mPssTable[i];
- int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long count = proc.mState.getLong(off, PSS_SAMPLE_COUNT);
- long min = proc.mState.getLong(off, PSS_MINIMUM);
- long avg = proc.mState.getLong(off, PSS_AVERAGE);
- long max = proc.mState.getLong(off, PSS_MAXIMUM);
- long umin = proc.mState.getLong(off, PSS_USS_MINIMUM);
- long uavg = proc.mState.getLong(off, PSS_USS_AVERAGE);
- long umax = proc.mState.getLong(off, PSS_USS_MAXIMUM);
- pw.print(',');
- printProcStateTag(pw, type);
- pw.print(':');
- pw.print(count);
- pw.print(':');
- pw.print(min);
- pw.print(':');
- pw.print(avg);
- pw.print(':');
- pw.print(max);
- pw.print(':');
- pw.print(umin);
- pw.print(':');
- pw.print(uavg);
- pw.print(':');
- pw.print(umax);
- }
- }
-
- 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;
- }
-
- static private void dumpHelp(PrintWriter pw) {
- pw.println("Process stats (procstats) dump options:");
- pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
- pw.println(" [--details] [--current] [--commit] [--write] [-h] [<package.name>]");
- pw.println(" --checkin: perform a checkin: print and delete old committed states.");
- pw.println(" --c: print only state in checkin format.");
- 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(" --details: dump all execution details, not just summary.");
- pw.println(" --current: only dump current state.");
- pw.println(" --commit: commit current stats to disk and reset to start new stats.");
- pw.println(" --write: write current in-memory stats to disk.");
- pw.println(" --read: replace current stats with last-written stats.");
- pw.println(" -a: print everything.");
- pw.println(" -h: print this help text.");
- pw.println(" <package.name>: optional name of package to filter output by.");
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- final long now = SystemClock.uptimeMillis();
-
- boolean isCheckin = false;
- boolean isCompact = false;
- boolean isCsv = false;
- boolean currentOnly = false;
- boolean dumpDetails = false;
- boolean dumpAll = 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 = ALL_PROC_STATES;
- if (args != null) {
- for (int i=0; i<args.length; i++) {
- String arg = args[i];
- if ("--checkin".equals(arg)) {
- isCheckin = true;
- } else if ("-c".equals(arg)) {
- isCompact = 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;
- }
- 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 ("--details".equals(arg)) {
- dumpDetails = true;
- } else if ("--current".equals(arg)) {
- currentOnly = true;
- } else if ("--commit".equals(arg)) {
- mState.mFlags |= State.FLAG_COMPLETE;
- mState.writeStateLocked(true, true);
- pw.println("Process stats committed.");
- return;
- } else if ("--write".equals(arg)) {
- writeStateSyncLocked();
- pw.println("Process stats written.");
- return;
- } else if ("--read".equals(arg)) {
- readLocked();
- pw.println("Process stats read.");
- return;
- } else if ("-h".equals(arg)) {
- dumpHelp(pw);
- return;
- } else if ("-a".equals(arg)) {
- dumpDetails = true;
- dumpAll = true;
- } 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 {
- IPackageManager pm = AppGlobals.getPackageManager();
- if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
- reqPackage = arg;
- // Include all details, since we know we are only going to
- // be dumping a smaller set of data. In fact only the details
- // container per-package data, so that are needed to be able
- // to dump anything at all when filtering by package.
- dumpDetails = true;
- }
- } catch (RemoteException e) {
- }
- if (reqPackage == null) {
- pw.println("Unknown package: " + arg);
- dumpHelp(pw);
- return;
- }
- }
- }
- }
-
- 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();
- synchronized (mLock) {
- dumpFilteredProcessesCsvLocked(pw, null,
- csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
- csvSepProcStats, csvProcStats, now, reqPackage);
- /*
- dumpFilteredProcessesCsvLocked(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);
- dumpFilteredProcessesCsvLocked(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;
- }
-
- boolean sepNeeded = false;
- if (!currentOnly || isCheckin) {
- mWriteLock.lock();
- try {
- ArrayList<String> files = getCommittedFiles(0, !isCheckin);
- if (files != null) {
- for (int i=0; i<files.size(); i++) {
- if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
- try {
- State state = new State(files.get(i));
- if (state.mReadError != null) {
- if (isCheckin || isCompact) pw.print("err,");
- pw.print("Failure reading "); pw.print(files.get(i));
- pw.print("; "); pw.println(state.mReadError);
- if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
- (new File(files.get(i))).delete();
- continue;
- }
- String fileStr = state.mFile.getBaseFile().getPath();
- boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
- if (isCheckin || isCompact) {
- // Don't really need to lock because we uniquely own this object.
- state.dumpCheckinLocked(pw, reqPackage);
- } else {
- if (sepNeeded) {
- pw.println();
- } else {
- sepNeeded = true;
- }
- pw.print("COMMITTED STATS FROM ");
- pw.print(state.mTimePeriodStartClockStr);
- if (checkedIn) pw.print(" (checked in)");
- pw.println(":");
- // Don't really need to lock because we uniquely own this object.
- if (dumpDetails) {
- state.dumpLocked(pw, reqPackage, now, dumpAll);
- } else {
- state.dumpSummaryLocked(pw, reqPackage, now);
- }
- }
- if (isCheckin) {
- // Rename file suffix to mark that it has checked in.
- state.mFile.getBaseFile().renameTo(new File(
- fileStr + STATE_FILE_CHECKIN_SUFFIX));
- }
- } catch (Throwable e) {
- pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
- e.printStackTrace(pw);
- }
- }
- }
- } finally {
- mWriteLock.unlock();
- }
- }
- if (!isCheckin) {
- synchronized (mLock) {
- if (isCompact) {
- mState.dumpCheckinLocked(pw, reqPackage);
- } else {
- if (sepNeeded) {
- pw.println();
- pw.println("CURRENT STATS:");
- }
- if (dumpDetails) {
- mState.dumpLocked(pw, reqPackage, now, dumpAll);
- } else {
- mState.dumpSummaryLocked(pw, reqPackage, now);
- }
- }
- }
- }
- }
-}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 14ccece..39756c3 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.NotificationManagerService;
@@ -83,7 +84,7 @@ final class ServiceRecord extends Binder {
ProcessRecord app; // where this service is running or null.
ProcessRecord isolatedProc; // keep track of isolated process, if requested
- ProcessTracker.ServiceState tracker; // tracking service execution, may be null
+ ProcessStats.ServiceState tracker; // tracking service execution, may be null
boolean isForeground; // is service currently in foreground mode?
int foregroundId; // Notification ID of last foreground req.
Notification foregroundNoti; // Notification record of foreground state.
@@ -310,12 +311,12 @@ final class ServiceRecord extends Binder {
createdFromFg = callerIsFg;
}
- public ProcessTracker.ServiceState getTracker() {
+ public ProcessStats.ServiceState getTracker() {
if (tracker != null) {
return tracker;
}
if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
- tracker = ams.mProcessTracker.getServiceStateLocked(serviceInfo.packageName,
+ tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name);
}
return tracker;