Merge "Use more styles for preferences to allow single pane 10""
diff --git a/api/current.txt b/api/current.txt
index 9df2a16..7f333b7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14819,7 +14819,6 @@
method public static synchronized android.nfc.cardemulation.CardEmulationManager getInstance(android.nfc.NfcAdapter);
method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
- method public boolean setDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.ACTION_CHANGE_DEFAULT";
field public static final java.lang.String CATEGORY_OTHER = "other";
field public static final java.lang.String CATEGORY_PAYMENT = "payment";
@@ -27257,13 +27256,15 @@
field public static final int SOUND_EFFECTS_ENABLED = 134217728; // 0x8000000
field public static final deprecated int STATUS_BAR_HIDDEN = 1; // 0x1
field public static final deprecated int STATUS_BAR_VISIBLE = 0; // 0x0
- field public static final int SYSTEM_UI_FLAG_ALLOW_OVERLAY = 2048; // 0x800
+ field public static final int SYSTEM_UI_FLAG_ALLOW_TRANSIENT = 2048; // 0x800
field public static final int SYSTEM_UI_FLAG_FULLSCREEN = 4; // 0x4
field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
field public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024; // 0x400
field public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512; // 0x200
field public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 256; // 0x100
field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
+ field public static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 8192; // 0x2000
+ field public static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 4096; // 0x1000
field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
field public static final int TEXT_ALIGNMENT_CENTER = 4; // 0x4
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index 7369c0b..b8a5ba7 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -28,5 +28,6 @@
boolean isDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
+ boolean setDefaultForNextTap(int userHandle, in ComponentName service);
List<ApduServiceInfo> getServices(int userHandle, in String category);
}
diff --git a/core/java/android/nfc/cardemulation/CardEmulationManager.java b/core/java/android/nfc/cardemulation/CardEmulationManager.java
index abfeaf9..673b33a 100644
--- a/core/java/android/nfc/cardemulation/CardEmulationManager.java
+++ b/core/java/android/nfc/cardemulation/CardEmulationManager.java
@@ -185,7 +185,7 @@
}
/**
- * @return
+ * @hide
*/
public boolean setDefaultServiceForCategory(ComponentName service, String category) {
try {
@@ -210,6 +210,27 @@
/**
* @hide
*/
+ public boolean setDefaultForNextTap(ComponentName service) {
+ try {
+ return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+ /**
+ * @hide
+ */
public List<ApduServiceInfo> getServices(String category) {
try {
return sService.getServices(UserHandle.myUserId(), category);
@@ -233,4 +254,4 @@
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
sService = adapter.getCardEmulationService();
}
-}
\ No newline at end of file
+}
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 @@
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 @@
data.writeStringArray(args);
try {
transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
- reply.readException();
} finally {
data.recycle();
reply.recycle();
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 9e8cfad..c067661 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -288,6 +288,7 @@
private void doFinish() {
mDocumentAdapter = null;
mHandler = null;
+ mLayoutOrWriteCancellation = null;
}
private final class MyHandler extends Handler {
@@ -312,10 +313,10 @@
case MSG_LAYOUT: {
SomeArgs args = (SomeArgs) message.obj;
- final PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
- final PrintAttributes newAttributes = (PrintAttributes) args.arg2;
- final ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
- final Bundle metadata = (Bundle) args.arg4;
+ PrintAttributes oldAttributes = (PrintAttributes) args.arg1;
+ PrintAttributes newAttributes = (PrintAttributes) args.arg2;
+ ILayoutResultCallback callback = (ILayoutResultCallback) args.arg3;
+ Bundle metadata = (Bundle) args.arg4;
final int sequence = args.argi1;
args.recycle();
@@ -324,49 +325,15 @@
mLayoutOrWriteCancellation = cancellation;
}
- mDocumentAdapter.onLayout(oldAttributes, newAttributes,
- cancellation, new LayoutResultCallback() {
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- if (info == null) {
- throw new IllegalArgumentException("info cannot be null");
- }
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- try {
- callback.onLayoutFinished(info, changed, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error) {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- try {
- callback.onLayoutFailed(error, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
- }
- }
-
- @Override
- public void onLayoutCancelled() {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- }
- }, metadata);
+ mDocumentAdapter.onLayout(oldAttributes, newAttributes, cancellation,
+ new MyLayoutResultCallback(callback, sequence), metadata);
} break;
case MSG_WRITE: {
SomeArgs args = (SomeArgs) message.obj;
- final PageRange[] pages = (PageRange[]) args.arg1;
- final FileDescriptor fd = (FileDescriptor) args.arg2;
- final IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
+ PageRange[] pages = (PageRange[]) args.arg1;
+ FileDescriptor fd = (FileDescriptor) args.arg2;
+ IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
final int sequence = args.argi1;
args.recycle();
@@ -376,52 +343,7 @@
}
mDocumentAdapter.onWrite(pages, fd, cancellation,
- new WriteResultCallback() {
- @Override
- public void onWriteFinished(PageRange[] pages) {
- if (pages == null) {
- throw new IllegalArgumentException("pages cannot be null");
- }
- if (pages.length == 0) {
- throw new IllegalArgumentException("pages cannot be empty");
- }
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- // Close before notifying the other end. We want
- // to be ready by the time we announce it.
- IoUtils.closeQuietly(fd);
- try {
- callback.onWriteFinished(pages, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFinished", re);
- }
- }
-
- @Override
- public void onWriteFailed(CharSequence error) {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- // Close before notifying the other end. We want
- // to be ready by the time we announce it.
- IoUtils.closeQuietly(fd);
- try {
- callback.onWriteFailed(error, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFailed", re);
- }
- }
-
- @Override
- public void onWriteCancelled() {
- synchronized (mLock) {
- mLayoutOrWriteCancellation = null;
- }
- // Just close the fd for now.
- IoUtils.closeQuietly(fd);
- }
- });
+ new MyWriteResultCallback(callback, fd, sequence));
} break;
case MSG_FINISH: {
@@ -436,5 +358,128 @@
}
}
}
+
+ private final class MyLayoutResultCallback extends LayoutResultCallback {
+ private ILayoutResultCallback mCallback;
+ private final int mSequence;
+
+ public MyLayoutResultCallback(ILayoutResultCallback callback,
+ int sequence) {
+ mCallback = callback;
+ mSequence = sequence;
+ }
+
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
+ final ILayoutResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (info == null) {
+ throw new IllegalArgumentException("info cannot be null");
+ }
+ if (callback != null) {
+ try {
+ callback.onLayoutFinished(info, changed, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
+ }
+ }
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error) {
+ final ILayoutResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (callback != null) {
+ try {
+ callback.onLayoutFailed(error, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
+ }
+ }
+ }
+
+ @Override
+ public void onLayoutCancelled() {
+ synchronized (mLock) {
+ clearLocked();
+ }
+ }
+
+ private void clearLocked() {
+ mLayoutOrWriteCancellation = null;
+ mCallback = null;
+ }
+ }
+
+ private final class MyWriteResultCallback extends WriteResultCallback {
+ private FileDescriptor mFd;
+ private int mSequence;
+ private IWriteResultCallback mCallback;
+
+ public MyWriteResultCallback(IWriteResultCallback callback,
+ FileDescriptor fd, int sequence) {
+ mFd = fd;
+ mSequence = sequence;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages) {
+ final IWriteResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (pages == null) {
+ throw new IllegalArgumentException("pages cannot be null");
+ }
+ if (pages.length == 0) {
+ throw new IllegalArgumentException("pages cannot be empty");
+ }
+ if (callback != null) {
+ try {
+ callback.onWriteFinished(pages, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFinished", re);
+ }
+ }
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error) {
+ final IWriteResultCallback callback;
+ synchronized (mLock) {
+ callback = mCallback;
+ clearLocked();
+ }
+ if (callback != null) {
+ try {
+ callback.onWriteFailed(error, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFailed", re);
+ }
+ }
+ }
+
+ @Override
+ public void onWriteCancelled() {
+ synchronized (mLock) {
+ clearLocked();
+ }
+ }
+
+ private void clearLocked() {
+ mLayoutOrWriteCancellation = null;
+ IoUtils.closeQuietly(mFd);
+ mCallback = null;
+ mFd = null;
+ }
+ }
}
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 52ad76d..b2c9f8c 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -322,7 +322,7 @@
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mSurface != null) {
- nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ mSurface.setDefaultBufferSize(getWidth(), getHeight());
updateLayer();
if (mListener != null) {
mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
@@ -362,7 +362,7 @@
// Create a new SurfaceTexture for the layer.
mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
}
- nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ mSurface.setDefaultBufferSize(getWidth(), getHeight());
nCreateNativeWindow(mSurface);
mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@@ -399,7 +399,7 @@
mMatrixChanged = true;
mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
- nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ mSurface.setDefaultBufferSize(getWidth(), getHeight());
}
applyUpdate();
@@ -816,9 +816,6 @@
private native void nCreateNativeWindow(SurfaceTexture surface);
private native void nDestroyNativeWindow();
- private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
- int width, int height);
-
private static native boolean nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7624b56..20938f51 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2379,9 +2379,27 @@
* when hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the
* navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} instead of having the system
* clear these flags upon interaction. The system may compensate by temporarily overlaying
- * transparent system ui while also delivering the event.
+ * transparent system bars while also delivering the event.
*/
- public static final int SYSTEM_UI_FLAG_ALLOW_OVERLAY = 0x00000800;
+ public static final int SYSTEM_UI_FLAG_ALLOW_TRANSIENT = 0x00000800;
+
+ /**
+ * Flag for {@link #setSystemUiVisibility(int)}: View would like the status bar to have
+ * transparency.
+ *
+ * <p>The transparency request may be denied if the bar is in another mode with a specific
+ * style, like {@link #SYSTEM_UI_FLAG_ALLOW_TRANSIENT transient mode}.
+ */
+ public static final int SYSTEM_UI_FLAG_TRANSPARENT_STATUS = 0x00001000;
+
+ /**
+ * Flag for {@link #setSystemUiVisibility(int)}: View would like the navigation bar to have
+ * transparency.
+ *
+ * <p>The transparency request may be denied if the bar is in another mode with a specific
+ * style, like {@link #SYSTEM_UI_FLAG_ALLOW_TRANSIENT transient mode}.
+ */
+ public static final int SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION = 0x00002000;
/**
* @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead.
@@ -2508,11 +2526,9 @@
* NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
* out of the public fields to keep the undefined bits out of the developer's way.
*
- * Flag to specify that the status bar should temporarily overlay underlying content
- * that is otherwise assuming the status bar is hidden. The status bar may
- * have some degree of transparency while in this temporary overlay mode.
+ * Flag to specify that the status bar is displayed in transient mode.
*/
- public static final int STATUS_BAR_OVERLAY = 0x04000000;
+ public static final int STATUS_BAR_TRANSIENT = 0x04000000;
/**
* @hide
@@ -2520,11 +2536,9 @@
* NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
* out of the public fields to keep the undefined bits out of the developer's way.
*
- * Flag to specify that the navigation bar should temporarily overlay underlying content
- * that is otherwise assuming the navigation bar is hidden. The navigation bar mayu
- * have some degree of transparency while in this temporary overlay mode.
+ * Flag to specify that the navigation bar is displayed in transient mode.
*/
- public static final int NAVIGATION_BAR_OVERLAY = 0x08000000;
+ public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000;
/**
* @hide
diff --git a/core/java/com/android/internal/os/ProcessStats.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
similarity index 98%
rename from core/java/com/android/internal/os/ProcessStats.java
rename to 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.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 @@
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 @@
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 @@
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 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 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 @@
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 @@
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 @@
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 @@
continue;
}
-
+
if (st == null || st.pid > pid) {
// We have a new process!
st = new Stats(pid, parentPid, mIncludeThreads);
@@ -477,7 +477,7 @@
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 @@
}
continue;
}
-
+
// This process has gone away!
st.rel_utime = 0;
st.rel_stime = 0;
@@ -520,7 +520,7 @@
NS--;
if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
}
-
+
return pids;
}
@@ -607,27 +607,27 @@
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 @@
}
return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
}
-
+
final void buildWorkingProcs() {
if (!mWorkingProcsSorted) {
mWorkingProcs.clear();
@@ -678,7 +678,7 @@
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 @@
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 @@
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 @@
}
}
}
-
+
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 @@
}
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/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 31b2cad..2c482ea 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -40,6 +40,7 @@
struct fields_t {
jfieldID surfaceTexture;
+ jfieldID bufferQueue;
jfieldID frameAvailableListener;
jmethodID postEvent;
};
@@ -61,6 +62,20 @@
env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
}
+static void SurfaceTexture_setBufferQueue(JNIEnv* env, jobject thiz,
+ const sp<BufferQueue>& bq)
+{
+ BufferQueue* const p =
+ (BufferQueue*)env->GetIntField(thiz, fields.bufferQueue);
+ if (bq.get()) {
+ bq->incStrong((void*)SurfaceTexture_setBufferQueue);
+ }
+ if (p) {
+ p->decStrong((void*)SurfaceTexture_setBufferQueue);
+ }
+ env->SetIntField(thiz, fields.bufferQueue, (int)bq.get());
+}
+
static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
jobject thiz, sp<GLConsumer::FrameAvailableListener> listener)
{
@@ -76,23 +91,22 @@
env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get());
}
-sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env,
- jobject thiz)
-{
+sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
return (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
}
-sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
- JNIEnv* env, jobject thiz)
-{
+sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
+ return (BufferQueue*)env->GetIntField(thiz, fields.bufferQueue);
+}
+
+sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz) {
sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
- sp<Surface> surfaceTextureClient(surfaceTexture != NULL ?
- new Surface(surfaceTexture->getBufferQueue()) : NULL);
+ sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
+ sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
return surfaceTextureClient;
}
-bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz)
-{
+bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
return env->IsInstanceOf(thiz, surfaceTextureClass);
}
@@ -175,6 +189,12 @@
// ----------------------------------------------------------------------------
+
+#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
+#define ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID "mBufferQueue"
+#define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \
+ "mFrameAvailableListener"
+
static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
{
fields.surfaceTexture = env->GetFieldID(clazz,
@@ -183,6 +203,12 @@
ALOGE("can't find android/graphics/SurfaceTexture.%s",
ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
}
+ fields.bufferQueue = env->GetFieldID(clazz,
+ ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID, "I");
+ if (fields.bufferQueue == NULL) {
+ ALOGE("can't find android/graphics/SurfaceTexture.%s",
+ ANDROID_GRAPHICS_BUFFERQUEUE_JNI_ID);
+ }
fields.frameAvailableListener = env->GetFieldID(clazz,
ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "I");
if (fields.frameAvailableListener == NULL) {
@@ -214,6 +240,7 @@
return;
}
SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
+ SurfaceTexture_setBufferQueue(env, thiz, bq);
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
@@ -234,11 +261,11 @@
surfaceTexture->setFrameAvailableListener(0);
SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
SurfaceTexture_setSurfaceTexture(env, thiz, 0);
+ SurfaceTexture_setBufferQueue(env, thiz, 0);
}
static void SurfaceTexture_setDefaultBufferSize(
- JNIEnv* env, jobject thiz, jint width, jint height)
-{
+ JNIEnv* env, jobject thiz, jint width, jint height) {
sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
surfaceTexture->setDefaultBufferSize(width, height);
}
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index dec4cd4..0018dd2 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -565,14 +565,10 @@
sp<Camera> camera = get_native_camera(env, thiz, NULL);
if (camera == 0) return;
- sp<BufferQueue> bufferQueue = NULL;
+ sp<IGraphicBufferProducer> producer = NULL;
if (jSurfaceTexture != NULL) {
- sp<GLConsumer> surfaceTexture =
- SurfaceTexture_getSurfaceTexture(env, jSurfaceTexture);
- if (surfaceTexture != NULL) {
- bufferQueue = surfaceTexture->getBufferQueue();
- }
- else {
+ producer = SurfaceTexture_getProducer(env, jSurfaceTexture);
+ if (producer == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"SurfaceTexture already released in setPreviewTexture");
return;
@@ -580,7 +576,7 @@
}
- if (camera->setPreviewTexture(bufferQueue) != NO_ERROR) {
+ if (camera->setPreviewTexture(producer) != NO_ERROR) {
jniThrowException(env, "java/io/IOException",
"setPreviewTexture failed");
}
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 48babb3..1fe4b08 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -604,7 +604,7 @@
jint _remaining;
EGLint *attrib_list = (EGLint *) 0;
android::sp<ANativeWindow> window;
- android::sp<android::GLConsumer> glConsumer;
+ android::sp<android::IGraphicBufferProducer> producer;
if (!attrib_list_ref) {
_exception = 1;
@@ -625,12 +625,12 @@
_exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface";
goto exit;
}
- glConsumer = android::SurfaceTexture_getSurfaceTexture(_env, win);
+ producer = android::SurfaceTexture_getProducer(_env, win);
- if (glConsumer == NULL)
+ if (producer == NULL)
goto not_valid_surface;
- window = new android::Surface(glConsumer->getBufferQueue());
+ window = new android::Surface(producer);
if (window == NULL)
goto not_valid_surface;
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 1007e7d..304514b 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -135,15 +135,14 @@
static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
jobject surfaceTextureObj) {
- sp<GLConsumer> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
- if (st == NULL) {
+ sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
+ if (producer == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"SurfaceTexture has already been released");
return 0;
}
- sp<IGraphicBufferProducer> bq = st->getBufferQueue();
- sp<Surface> surface(new Surface(bq, true));
+ sp<Surface> surface(new Surface(producer, true));
if (surface == NULL) {
jniThrowException(env, OutOfResourcesException, NULL);
return 0;
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index d515696..8dc2fc6 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -69,13 +69,6 @@
// Native layer
// ----------------------------------------------------------------------------
-static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
- jobject surface, jint width, jint height) {
-
- sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
- glConsumer->setDefaultBufferSize(width, height);
-}
-
static inline SkBitmap::Config convertPixelFormat(int32_t format) {
switch (format) {
case WINDOW_FORMAT_RGBA_8888:
@@ -106,8 +99,8 @@
static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView,
jobject surface) {
- sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
- sp<ANativeWindow> window = new Surface(glConsumer->getBufferQueue());
+ sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surface));
+ sp<ANativeWindow> window = new Surface(producer);
window->incStrong((void*)android_view_TextureView_createNativeWindow);
SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
@@ -208,9 +201,6 @@
const char* const kClassPathName = "android/view/TextureView";
static JNINativeMethod gMethods[] = {
- { "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V",
- (void*) android_view_TextureView_setDefaultBufferSize },
-
{ "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
(void*) android_view_TextureView_createNativeWindow },
{ "nDestroyNativeWindow", "()V",
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index b0c73a2..a3ce2a5 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -352,9 +352,8 @@
return 0;
}
- sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(_env, native_window));
-
- window = new Surface(glConsumer->getBufferQueue());
+ sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(_env, native_window));
+ window = new Surface(producer);
if (window == NULL)
goto not_valid_surface;
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 91deb87..e8d6f16 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -69,6 +69,7 @@
* These fields are used by native code, do not access or modify.
*/
private int mSurfaceTexture;
+ private int mBufferQueue;
private int mFrameAvailableListener;
/**
diff --git a/include/android_runtime/android_graphics_SurfaceTexture.h b/include/android_runtime/android_graphics_SurfaceTexture.h
index 77ccd2a..c534d4b 100644
--- a/include/android_runtime/android_graphics_SurfaceTexture.h
+++ b/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -24,14 +24,17 @@
namespace android {
class GLConsumer;
+class IGraphicBufferProducer;
-extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(
- JNIEnv* env, jobject thiz);
+extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz);
extern bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz);
/* Gets the underlying GLConsumer from a SurfaceTexture Java object. */
extern sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz);
+/* gets the producer end of the SurfaceTexture */
+extern sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz);
+
} // namespace android
#endif // _ANDROID_GRAPHICS_SURFACETEXTURE_H
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index b36f1400..60a84a6 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -2141,7 +2141,7 @@
new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
}
- protected void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
+ private void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
+ ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
synchronized(mRCStack) {
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0646f98..0b429f6 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/List.h>
+#include <utils/String8.h>
#include <cstdio>
@@ -47,22 +48,20 @@
IMAGE_READER_MAX_NUM_PLANES = 3,
};
-struct fields_t {
- // For ImageReader class
- jfieldID imageReaderContext;
- jmethodID postEvent;
- // For SurfaceImage class
- jfieldID buffer;
- jfieldID timeStamp;
-};
+static struct {
+ jfieldID mNativeContext;
+ jmethodID postEventFromNative;
+} gImageReaderClassInfo;
-struct classInfo_t {
+static struct {
+ jfieldID mLockedBuffer;
+ jfieldID mTimestamp;
+} gSurfaceImageClassInfo;
+
+static struct {
jclass clazz;
jmethodID ctor;
-};
-
-static fields_t fields;
-static classInfo_t surfPlaneClassInfo;
+} gSurfacePlaneClassInfo;
// ----------------------------------------------------------------------------
@@ -79,9 +78,11 @@
void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer);
+ void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; }
CpuConsumer* getCpuConsumer() { return mConsumer.get(); }
- void setCpuConsumer(sp<CpuConsumer> consumer) { mConsumer = consumer; }
+ void setBufferQueue(const sp<BufferQueue>& bq) { mBufferQueue = bq; }
+ BufferQueue* getBufferQueue() { return mBufferQueue.get(); }
void setBufferFormat(int format) { mFormat = format; }
int getBufferFormat() { return mFormat; }
@@ -98,6 +99,7 @@
List<CpuConsumer::LockedBuffer*> mBuffers;
sp<CpuConsumer> mConsumer;
+ sp<BufferQueue> mBufferQueue;
jobject mWeakThiz;
jclass mClazz;
int mFormat;
@@ -183,7 +185,7 @@
bool needsDetach = false;
JNIEnv* env = getJNIEnv(&needsDetach);
if (env != NULL) {
- env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
+ env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz);
} else {
ALOGW("onFrameAvailable event will not posted");
}
@@ -200,7 +202,7 @@
{
JNIImageReaderContext *ctx;
ctx = reinterpret_cast<JNIImageReaderContext *>
- (env->GetLongField(thiz, fields.imageReaderContext));
+ (env->GetLongField(thiz, gImageReaderClassInfo.mNativeContext));
return ctx;
}
@@ -215,6 +217,17 @@
return ctx->getCpuConsumer();
}
+static BufferQueue* ImageReader_getBufferQueue(JNIEnv* env, jobject thiz)
+{
+ ALOGV("%s:", __FUNCTION__);
+ JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
+ if (ctx == NULL) {
+ jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
+ return NULL;
+ }
+ return ctx->getBufferQueue();
+}
+
static void ImageReader_setNativeContext(JNIEnv* env,
jobject thiz, sp<JNIImageReaderContext> ctx)
{
@@ -226,18 +239,20 @@
if (p) {
p->decStrong((void*)ImageReader_setNativeContext);
}
- env->SetLongField(thiz, fields.imageReaderContext, reinterpret_cast<jlong>(ctx.get()));
+ env->SetLongField(thiz, gImageReaderClassInfo.mNativeContext,
+ reinterpret_cast<jlong>(ctx.get()));
}
static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image)
{
- return reinterpret_cast<CpuConsumer::LockedBuffer*>(env->GetLongField(image, fields.buffer));
+ return reinterpret_cast<CpuConsumer::LockedBuffer*>(
+ env->GetLongField(image, gSurfaceImageClassInfo.mLockedBuffer));
}
static void Image_setBuffer(JNIEnv* env, jobject thiz,
const CpuConsumer::LockedBuffer* buffer)
{
- env->SetLongField(thiz, fields.buffer, reinterpret_cast<jlong>(buffer));
+ env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer));
}
// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
@@ -549,33 +564,37 @@
jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage");
LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
"can't find android/graphics/ImageReader$SurfaceImage");
- fields.buffer = env->GetFieldID(imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J");
- LOG_ALWAYS_FATAL_IF(fields.buffer == NULL,
+ gSurfaceImageClassInfo.mLockedBuffer = env->GetFieldID(
+ imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J");
+ LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mLockedBuffer == NULL,
"can't find android/graphics/ImageReader.%s",
ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID);
- fields.timeStamp = env->GetFieldID(imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J");
- LOG_ALWAYS_FATAL_IF(fields.timeStamp == NULL,
+ gSurfaceImageClassInfo.mTimestamp = env->GetFieldID(
+ imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J");
+ LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTimestamp == NULL,
"can't find android/graphics/ImageReader.%s",
ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
- fields.imageReaderContext = env->GetFieldID(clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
- LOG_ALWAYS_FATAL_IF(fields.imageReaderContext == NULL,
+ gImageReaderClassInfo.mNativeContext = env->GetFieldID(
+ clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
+ LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL,
"can't find android/graphics/ImageReader.%s",
ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID);
- fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
- "(Ljava/lang/Object;)V");
- LOG_ALWAYS_FATAL_IF(fields.postEvent == NULL,
+ gImageReaderClassInfo.postEventFromNative = env->GetStaticMethodID(
+ clazz, "postEventFromNative", "(Ljava/lang/Object;)V");
+ LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.postEventFromNative == NULL,
"can't find android/graphics/ImageReader.postEventFromNative");
jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane");
LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class");
// FindClass only gives a local reference of jclass object.
- surfPlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
- surfPlaneClassInfo.ctor = env->GetMethodID(surfPlaneClassInfo.clazz, "<init>",
- "(Landroid/media/ImageReader$SurfaceImage;III)V");
- LOG_ALWAYS_FATAL_IF(surfPlaneClassInfo.ctor == NULL, "Can not find SurfacePlane constructor");
+ gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
+ gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
+ "(Landroid/media/ImageReader$SurfaceImage;III)V");
+ LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
+ "Can not find SurfacePlane constructor");
}
static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
@@ -604,6 +623,7 @@
}
sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
ctx->setCpuConsumer(consumer);
+ ctx->setBufferQueue(bq);
consumer->setFrameAvailableListener(ctx);
ImageReader_setNativeContext(env, thiz, ctx);
ctx->setBufferFormat(nativeFormat);
@@ -710,8 +730,8 @@
int imageReaderWidth = ctx->getBufferWidth();
int imageReaderHeight = ctx->getBufferHeight();
- if ((imageReaderWidth != outputWidth) ||
- (imageReaderHeight != outputHeight)) {
+ if (imageReaderWidth != outputWidth
+ || imageReaderHeight != outputHeight) {
// Spew warning for now, since MediaCodec decoder has a bug to setup the right crop
// TODO: make it throw exception once the decoder bug is fixed.
ALOGW("Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
@@ -726,14 +746,18 @@
// Throw exception
ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
buffer->format, ctx->getBufferFormat());
+ String8 msg;
+ msg.appendFormat("The producer output buffer format 0x%x doesn't "
+ "match the ImageReader's configured buffer format 0x%x.",
+ buffer->format, ctx->getBufferFormat());
jniThrowException(env, "java/lang/UnsupportedOperationException",
- "The producer output buffer configuration doesn't match the ImageReader"
- "configured");
+ msg.string());
return false;
}
// Set SurfaceImage instance member variables
Image_setBuffer(env, image, buffer);
- env->SetLongField(image, fields.timeStamp, static_cast<jlong>(buffer->timestamp));
+ env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
+ static_cast<jlong>(buffer->timestamp));
return true;
}
@@ -742,15 +766,14 @@
{
ALOGV("%s: ", __FUNCTION__);
- CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz);
- if (consumer == NULL) {
+ BufferQueue* bq = ImageReader_getBufferQueue(env, thiz);
+ if (bq == NULL) {
jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
return NULL;
}
// Wrap the IGBP in a Java-language Surface.
- return android_view_Surface_createFromIGraphicBufferProducer(env,
- consumer->getProducerInterface());
+ return android_view_Surface_createFromIGraphicBufferProducer(env, bq);
}
static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx)
@@ -767,8 +790,8 @@
rowStride = Image_imageGetRowStride(env, buffer, idx);
pixelStride = Image_imageGetPixelStride(env, buffer, idx);
- jobject surfPlaneObj = env->NewObject(surfPlaneClassInfo.clazz, surfPlaneClassInfo.ctor,
- thiz, idx, rowStride, pixelStride);
+ jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
+ gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
return surfPlaneObj;
}
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp
index 63fd16e..fdecda3 100644
--- a/media/mca/filterfw/native/core/gl_env.cpp
+++ b/media/mca/filterfw/native/core/gl_env.cpp
@@ -162,8 +162,7 @@
// Create dummy surface using a GLConsumer
sp<BufferQueue> bq = new BufferQueue();
surfaceTexture_ = new GLConsumer(bq, 0);
- window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(
- surfaceTexture_->getBufferQueue()));
+ window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(bq));
surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
if (CheckEGLError("eglCreateWindowSurface")) return false;
diff --git a/packages/PrintSpooler/res/layout/generating_print_job_dialog.xml b/packages/PrintSpooler/res/layout/generating_print_job_dialog.xml
new file mode 100644
index 0000000..360f8434
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/generating_print_job_dialog.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/progress"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dip"
+ android:layout_gravity="center_horizontal"
+ style="?android:attr/progressBarStyleLarge">
+</ProgressBar>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity.xml b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
index a4105ea..1a8b0f1 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity.xml
@@ -14,274 +14,276 @@
limitations under the License.
-->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:scrollbars="vertical">
+ android:orientation="vertical">
- <GridLayout
- android:layout_width="wrap_content"
+ <ScrollView
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:columnCount="2">
+ android:scrollbars="vertical">
- <!-- Destination -->
-
- <Spinner
- android:id="@+id/destination_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_marginLeft="32dip"
- android:layout_marginTop="32dip"
- android:layout_marginRight="32dip"
- android:layout_marginBottom="12dip"
- android:layout_row="0"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Spinner>
-
- <!-- Copies -->
-
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/copies_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="32dip"
- android:layout_marginRight="12dip"
- android:layout_marginBottom="12dip"
- android:layout_row="2"
- android:layout_column="0"
- android:layout_gravity="bottom"
- android:inputType="numberDecimal"
- android:selectAllOnFocus="true"
- android:minWidth="150dip"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </view>
-
- <TextView
+ <GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="32dip"
- android:layout_marginTop="12dip"
- android:layout_marginRight="12dip"
- android:layout_row="1"
- android:layout_column="0"
- android:layout_gravity="left|bottom"
- android:text="@string/label_copies"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/copies_edittext">
- </TextView>
+ android:orientation="vertical"
+ android:columnCount="2">
- <!-- Paper size -->
+ <!-- Destination -->
- <Spinner
- android:id="@+id/paper_size_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="32dip"
- android:layout_marginBottom="12dip"
- android:layout_row="2"
- android:layout_column="1"
- android:minWidth="150dip"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Spinner>
+ <Spinner
+ android:id="@+id/destination_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="0"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </Spinner>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="32dip"
- android:layout_marginTop="12dip"
- android:layout_row="1"
- android:layout_column="1"
- android:text="@string/label_paper_size"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/paper_size_spinner">
- </TextView>
+ <!-- Copies -->
- <!-- Color -->
+ <view
+ class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+ android:id="@+id/copies_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="12dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="2"
+ android:layout_column="0"
+ android:layout_gravity="bottom"
+ android:inputType="numberDecimal"
+ android:selectAllOnFocus="true"
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </view>
- <Spinner
- android:id="@+id/color_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="32dip"
- android:layout_marginRight="12dip"
- android:layout_marginBottom="12dip"
- android:layout_row="4"
- android:layout_column="0"
- android:minWidth="150dip"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Spinner>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="1"
+ android:layout_column="0"
+ android:layout_gravity="left|bottom"
+ android:text="@string/label_copies"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/copies_edittext">
+ </TextView>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="32dip"
- android:layout_marginTop="12dip"
- android:layout_marginRight="12dip"
- android:layout_row="3"
- android:layout_column="0"
- android:text="@string/label_color"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/color_spinner">
- </TextView>
+ <!-- Paper size -->
- <!-- Orientation -->
+ <Spinner
+ android:id="@+id/paper_size_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="2"
+ android:layout_column="1"
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </Spinner>
- <Spinner
- android:id="@+id/orientation_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="32dip"
- android:layout_marginBottom="12dip"
- android:layout_row="4"
- android:layout_column="1"
- android:minWidth="150dip"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Spinner>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_row="1"
+ android:layout_column="1"
+ android:text="@string/label_paper_size"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/paper_size_spinner">
+ </TextView>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginTop="12dip"
- android:layout_marginRight="32dip"
- android:layout_row="3"
- android:layout_column="1"
- android:text="@string/label_orientation"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/orientation_spinner">
- </TextView>
+ <!-- Color -->
- <!-- Pages -->
+ <Spinner
+ android:id="@+id/color_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="12dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="4"
+ android:layout_column="0"
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </Spinner>
- <Spinner
- android:id="@+id/range_options_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="32dip"
- android:layout_marginRight="12dip"
- android:layout_row="6"
- android:layout_column="0"
- android:minWidth="150dip"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Spinner>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="3"
+ android:layout_column="0"
+ android:text="@string/label_color"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/color_spinner">
+ </TextView>
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/page_range_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="32dip"
- android:layout_row="6"
- android:layout_column="1"
- android:layout_gravity="bottom"
- android:selectAllOnFocus="true"
- android:minWidth="150dip"
- android:hint="@string/pages_range_example"
- android:inputType="textNoSuggestions"
- android:visibility="gone"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </view>
+ <!-- Orientation -->
- <TextView
- android:id="@+id/page_range_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="32dip"
- android:layout_marginTop="12dip"
- android:layout_marginRight="12dip"
- android:layout_row="5"
- android:layout_column="0"
- android:text="@string/label_pages"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textStyle="bold"
- android:labelFor="@id/range_options_spinner">
- </TextView>
+ <Spinner
+ android:id="@+id/orientation_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="12dip"
+ android:layout_row="4"
+ android:layout_column="1"
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </Spinner>
- <!-- Print pereview -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="3"
+ android:layout_column="1"
+ android:text="@string/label_orientation"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/orientation_spinner">
+ </TextView>
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_marginLeft="32dip"
- android:layout_marginTop="32dip"
- android:layout_marginRight="32dip"
- android:layout_row="7"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:background="?android:attr/listDivider"
- android:contentDescription="@null">
- </ImageView>
+ <!-- Pages -->
- <Button
- android:id="@+id/print_preview_button"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_marginLeft="32dip"
- android:layout_marginRight="32dip"
- android:layout_row="8"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:text="@string/print_preview"
- android:gravity="left|center_vertical"
- android:background="?android:attr/selectableItemBackground"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Button>
+ <Spinner
+ android:id="@+id/range_options_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="6"
+ android:layout_column="0"
+ android:minWidth="150dip"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </Spinner>
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_marginLeft="32dip"
- android:layout_marginRight="32dip"
- android:layout_marginBottom="32dip"
- android:layout_row="9"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:background="?android:attr/listDivider"
- android:contentDescription="@null">
- </ImageView>
+ <view
+ class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+ android:id="@+id/page_range_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="6"
+ android:layout_column="1"
+ android:layout_gravity="bottom"
+ android:selectAllOnFocus="true"
+ android:minWidth="150dip"
+ android:hint="@string/pages_range_example"
+ android:inputType="textNoSuggestions"
+ android:visibility="gone"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </view>
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_row="10"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:background="?android:attr/listDivider"
- android:contentDescription="@null">
- </ImageView>
+ <TextView
+ android:id="@+id/page_range_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="12dip"
+ android:layout_marginRight="12dip"
+ android:layout_row="5"
+ android:layout_column="0"
+ android:text="@string/label_pages"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"
+ android:labelFor="@id/range_options_spinner">
+ </TextView>
- <Button
- android:id="@+id/print_button"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_row="11"
- android:layout_column="0"
- android:layout_columnSpan="2"
- android:padding="0dip"
- android:text="@string/print_button"
- android:background="?android:attr/selectableItemBackground"
- android:minHeight="?android:attr/listPreferredItemHeight">
- </Button>
+ <!-- Print pereview -->
- </GridLayout>
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginTop="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="7"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:background="?android:attr/listDivider"
+ android:contentDescription="@null">
+ </ImageView>
-</ScrollView>
+ <Button
+ android:id="@+id/print_preview_button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_row="8"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:text="@string/print_preview"
+ android:gravity="left|center_vertical"
+ android:background="?android:attr/selectableItemBackground"
+ android:minHeight="?android:attr/listPreferredItemHeight">
+ </Button>
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="32dip"
+ android:layout_marginBottom="32dip"
+ android:layout_row="9"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:background="?android:attr/listDivider"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:layout_row="10"
+ android:layout_column="0"
+ android:layout_columnSpan="2"
+ android:background="?android:attr/listDivider"
+ android:contentDescription="@null">
+ </ImageView>
+
+ </GridLayout>
+
+ </ScrollView>
+
+ <Button
+ android:id="@+id/print_button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:text="@string/print_button"
+ style="?android:attr/buttonBarButtonStyle">
+ </Button>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index f400f21..fbddf43 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -55,10 +55,10 @@
<!-- Title if the number of pages in a printed document is unknown. [CHAR LIMIT=20] -->
<string name="page_count_unknown">unknown</string>
- <!-- Notifications -->
+ <!-- Title for the temporary dialog show while an app is generating a print job. [CHAR LIMIT=30] -->
+ <string name="generating_print_job">Generating print job</string>
- <!-- Template for the notificaiton label for a queued print job. [CHAR LIMIT=25] -->
- <string name="queued_notification_title_template">Queued <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
+ <!-- Notifications -->
<!-- Template for the notificaiton label for a printing print job. [CHAR LIMIT=25] -->
<string name="printing_notification_title_template">Printing <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
@@ -75,6 +75,9 @@
<!-- Label for the notification button for restrating a filed print job. [CHAR LIMIT=25] -->
<string name="restart">Restart</string>
+ <!-- Message that there is no connection to a printer. [CHAR LIMIT=40] -->
+ <string name="no_connection_to_printer">No connection to printer</string>
+
<!-- Arrays -->
<!-- Color mode labels. -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
index 14a96c9..8b49c0e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
@@ -65,10 +65,6 @@
}
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED: {
- createQueuingNotificaiton(printJob);
- } break;
-
- case PrintJobInfo.STATE_STARTED: {
createPrintingNotificaiton(printJob);
} break;
@@ -83,22 +79,6 @@
}
}
- private void createQueuingNotificaiton(PrintJobInfo printJob) {
- Notification.Builder builder = new Notification.Builder(mContext)
- // TODO: Use appropriate icon when assets are ready
- .setSmallIcon(android.R.drawable.ic_secure)
- .setContentTitle(mContext.getString(R.string.queued_notification_title_template,
- printJob.getLabel()))
- // TODO: Use appropriate icon when assets are ready
- .addAction(android.R.drawable.ic_secure, mContext.getString(R.string.cancel),
- createCancelIntent(printJob))
- .setContentText(printJob.getPrinterId().getPrinterName())
- .setWhen(System.currentTimeMillis())
- .setOngoing(true)
- .setShowWhen(true);
- mNotificationManager.notify(printJob.getId(), builder.build());
- }
-
private void createPrintingNotificaiton(PrintJobInfo printJob) {
Notification.Builder builder = new Notification.Builder(mContext)
// TODO: Use appropriate icon when assets are ready
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 15c2b2f..00a76b8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -17,7 +17,11 @@
package com.android.printspooler;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -66,6 +70,7 @@
import android.widget.TextView;
import android.widget.Toast;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -137,6 +142,8 @@
private IBinder mIPrintDocumentAdapter;
+ private Dialog mGeneratingPrintJobDialog;
+
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
@@ -167,17 +174,14 @@
mController = new PrintController(new RemotePrintDocumentAdapter(
IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
mSpooler.generateFileForPrintJob(mPrintJobId)));
- }
- @Override
- protected void onResume() {
- super.onResume();
try {
mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException re) {
finish();
return;
}
+
mController.initialize();
mEditor.initialize();
mPrinterDiscoveryObserver = new PrinterDiscoveryObserver(mEditor, getMainLooper());
@@ -185,27 +189,29 @@
}
@Override
- protected void onPause() {
+ protected void onDestroy() {
+ // We can safely do the work in here since at this point
+ // the system is bound to our (spooler) process which
+ // guarantees that this process will not be killed.
mSpooler.stopPrinterDiscovery();
mPrinterDiscoveryObserver.destroy();
mPrinterDiscoveryObserver = null;
- if (mController.isCancelled() || mController.isFailed()) {
+ if (mController.hasStarted()) {
+ mController.finish();
+ }
+ if (mEditor.isPrintConfirmed() && mController.isFinished()) {
+ mSpooler.setPrintJobState(mPrintJobId,
+ PrintJobInfo.STATE_QUEUED, null);
+ } else {
mSpooler.setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_CANCELED, null);
- } else if (mController.hasStarted()) {
- mController.finish();
- if (mEditor.isPrintConfirmed()) {
- if (mController.isFinished()) {
- mSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_QUEUED, null);
- } else {
- mSpooler.setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_CANCELED, null);
- }
- }
}
mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
- super.onPause();
+ if (mGeneratingPrintJobDialog != null) {
+ mGeneratingPrintJobDialog.dismiss();
+ mGeneratingPrintJobDialog = null;
+ }
+ super.onDestroy();
}
public boolean onTouchEvent(MotionEvent event) {
@@ -243,56 +249,54 @@
return !mOldPrintAttributes.equals(mCurrPrintAttributes);
}
+ private void showGeneratingPrintJobUi() {
+ getWindow().getDecorView().setVisibility(View.GONE);
+
+ DialogFragment fragment = new DialogFragment() {
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return new AlertDialog.Builder(PrintJobConfigActivity.this)
+ .setTitle(getString(R.string.generating_print_job))
+ .setView(PrintJobConfigActivity.this.getLayoutInflater().inflate(
+ R.layout.generating_print_job_dialog, null))
+ .setCancelable(false)
+ .setPositiveButton(getString(R.string.cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mEditor.cancel();
+ PrintJobConfigActivity.this.finish();
+ }
+ })
+ .create();
+ }
+ };
+ fragment.show(getFragmentManager(), getString(R.string.generating_print_job));
+ }
+
private class PrintController {
private final AtomicInteger mRequestCounter = new AtomicInteger();
private final RemotePrintDocumentAdapter mRemotePrintAdapter;
- private final Handler mHandler;
+ private final Bundle mMetadata;
+
+ private final ControllerHandler mHandler;
+
+ private final LayoutResultCallback mLayoutResultCallback;
+
+ private final WriteResultCallback mWriteResultCallback;
private int mControllerState = CONTROLLER_STATE_INITIALIZED;
private PageRange[] mRequestedPages;
- private Bundle mMetadata = new Bundle();
-
- private final ILayoutResultCallback mILayoutResultCallback =
- new ILayoutResultCallback.Stub() {
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FINISHED, changed ? 1 : 0,
- 0, info).sendToTarget();
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT_FAILED, error).sendToTarget();
- }
- }
- };
-
- private IWriteResultCallback mIWriteResultCallback = new IWriteResultCallback.Stub() {
- @Override
- public void onWriteFinished(PageRange[] pages, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FINISHED, pages).sendToTarget();
- }
- }
-
- @Override
- public void onWriteFailed(CharSequence error, int sequence) {
- if (mRequestCounter.get() == sequence) {
- mHandler.obtainMessage(MyHandler.MSG_ON_WRITE_FAILED, error).sendToTarget();
- }
- }
- };
-
public PrintController(RemotePrintDocumentAdapter adapter) {
mRemotePrintAdapter = adapter;
- mHandler = new MyHandler(Looper.getMainLooper());
+ mMetadata = new Bundle();
+ mHandler = new ControllerHandler(getMainLooper());
+ mLayoutResultCallback = new LayoutResultCallback(mHandler);
+ mWriteResultCallback = new WriteResultCallback(mHandler);
}
public void initialize() {
@@ -311,10 +315,6 @@
return (mControllerState == CONTROLLER_STATE_FINISHED);
}
- public boolean isFailed() {
- return (mControllerState == CONTROLLER_STATE_FAILED);
- }
-
public boolean hasStarted() {
return mControllerState >= CONTROLLER_STATE_STARTED;
}
@@ -338,7 +338,7 @@
// If the attributes changes, then we do not do a layout but may
// have to ask the app to write some pages. Hence, pretend layout
// completed and nothing changed, so we handle writing as usual.
- handleOnLayoutFinished(mDocument.info, false);
+ handleOnLayoutFinished(mDocument.info, false, mRequestCounter.get());
} else {
mSpooler.setPrintJobAttributesNoPersistence(mPrintJobId, mCurrPrintAttributes);
@@ -348,7 +348,7 @@
mControllerState = CONTROLLER_STATE_LAYOUT_STARTED;
mRemotePrintAdapter.layout(mOldPrintAttributes, mCurrPrintAttributes,
- mILayoutResultCallback, mMetadata, mRequestCounter.incrementAndGet());
+ mLayoutResultCallback, mMetadata, mRequestCounter.incrementAndGet());
mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
}
@@ -359,7 +359,12 @@
mRemotePrintAdapter.finish();
}
- private void handleOnLayoutFinished(PrintDocumentInfo info, boolean layoutChanged) {
+ private void handleOnLayoutFinished(PrintDocumentInfo info,
+ boolean layoutChanged, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
+
if (isCancelled()) {
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
@@ -421,18 +426,25 @@
// Request a write of the pages of interest.
mControllerState = CONTROLLER_STATE_WRITE_STARTED;
- mRemotePrintAdapter.write(mRequestedPages, mIWriteResultCallback,
+ mRemotePrintAdapter.write(mRequestedPages, mWriteResultCallback,
mRequestCounter.incrementAndGet());
}
- private void handleOnLayoutFailed(CharSequence error) {
+ private void handleOnLayoutFailed(CharSequence error, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
mControllerState = CONTROLLER_STATE_FAILED;
// TODO: We need some UI for announcing an error.
Log.e(LOG_TAG, "Error during layout: " + error);
PrintJobConfigActivity.this.finish();
}
- private void handleOnWriteFinished(PageRange[] pages) {
+ private void handleOnWriteFinished(PageRange[] pages, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
+
if (isCancelled()) {
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
@@ -490,19 +502,22 @@
}
}
- private void handleOnWriteFailed(CharSequence error) {
+ private void handleOnWriteFailed(CharSequence error, int sequence) {
+ if (mRequestCounter.get() != sequence) {
+ return;
+ }
mControllerState = CONTROLLER_STATE_FAILED;
Log.e(LOG_TAG, "Error during write: " + error);
PrintJobConfigActivity.this.finish();
}
- private final class MyHandler extends Handler {
+ private final class ControllerHandler extends Handler {
public static final int MSG_ON_LAYOUT_FINISHED = 1;
public static final int MSG_ON_LAYOUT_FAILED = 2;
public static final int MSG_ON_WRITE_FINISHED = 3;
public static final int MSG_ON_WRITE_FAILED = 4;
- public MyHandler(Looper looper) {
+ public ControllerHandler(Looper looper) {
super(looper, null, false);
}
@@ -512,28 +527,84 @@
case MSG_ON_LAYOUT_FINISHED: {
PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
final boolean changed = (message.arg1 == 1);
- mController.handleOnLayoutFinished(info, changed);
+ final int sequence = message.arg2;
+ handleOnLayoutFinished(info, changed, sequence);
} break;
case MSG_ON_LAYOUT_FAILED: {
CharSequence error = (CharSequence) message.obj;
- mController.handleOnLayoutFailed(error);
+ final int sequence = message.arg1;
+ handleOnLayoutFailed(error, sequence);
} break;
case MSG_ON_WRITE_FINISHED: {
PageRange[] pages = (PageRange[]) message.obj;
- mController.handleOnWriteFinished(pages);
+ final int sequence = message.arg1;
+ handleOnWriteFinished(pages, sequence);
} break;
case MSG_ON_WRITE_FAILED: {
CharSequence error = (CharSequence) message.obj;
- mController.handleOnWriteFailed(error);
+ final int sequence = message.arg1;
+ handleOnWriteFailed(error, sequence);
} break;
}
}
}
}
+ private static final class LayoutResultCallback extends ILayoutResultCallback.Stub {
+ private final WeakReference<PrintController.ControllerHandler> mWeakHandler;
+
+ public LayoutResultCallback(PrintController.ControllerHandler handler) {
+ mWeakHandler = new WeakReference<PrintController.ControllerHandler>(handler);
+ }
+
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_LAYOUT_FINISHED,
+ changed ? 1 : 0, sequence, info).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_LAYOUT_FAILED,
+ sequence, 0, error).sendToTarget();
+ }
+ }
+ }
+
+ private static final class WriteResultCallback extends IWriteResultCallback.Stub {
+ private final WeakReference<PrintController.ControllerHandler> mWeakHandler;
+
+ public WriteResultCallback(PrintController.ControllerHandler handler) {
+ mWeakHandler = new WeakReference<PrintController.ControllerHandler>(handler);
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_WRITE_FINISHED,
+ sequence, 0, pages).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_WRITE_FAILED,
+ sequence, 0, error).sendToTarget();
+ }
+ }
+ }
+
private final class Editor {
private final EditText mCopiesEditText;
@@ -837,6 +908,7 @@
mEditor.confirmPrint();
updateUi();
mController.update();
+ showGeneratingPrintJobUi();
}
});
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
index 0bc20a3..00e05bb 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
@@ -177,17 +177,15 @@
// Update the notification.
mNotificationController.onPrintJobStateChanged(printJob);
- //TODO: Figure out what the right policy for read print jobs is.
-
switch (printJob.getState()) {
- case PrintJobInfo.STATE_QUEUED: {
- // Notify that we have a queued job.
- mService.onPrintJobQueued(new PrintJobInfo(printJob));
- } break;
-
+ case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
- // We really want to restart this print job.
- setPrintJobState(printJob.getId(), PrintJobInfo.STATE_QUEUED, null);
+ // We have a print job that was queued or started in the past
+ // but the device battery died or a crash occurred. In this case
+ // we assume the print job failed and let the user decide whether
+ // to restart the job or just
+ setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED,
+ mService.getString(R.string.no_connection_to_printer));
} break;
}
}
diff --git a/packages/SystemUI/res/values-land/refs.xml b/packages/SystemUI/res/values-land/refs.xml
index f5e79b9..62fb77d 100644
--- a/packages/SystemUI/res/values-land/refs.xml
+++ b/packages/SystemUI/res/values-land/refs.xml
@@ -16,5 +16,5 @@
*/
-->
<resources>
- <item type="string" name="hideybar_confirmation_message">@string/hideybar_confirmation_message_long</item>
+ <item type="string" name="hiding_navigation_confirmation_message">@string/hiding_navigation_confirmation_message_long</item>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/refs.xml b/packages/SystemUI/res/values-sw600dp-port/refs.xml
index f5e79b9..62fb77d 100644
--- a/packages/SystemUI/res/values-sw600dp-port/refs.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/refs.xml
@@ -16,5 +16,5 @@
*/
-->
<resources>
- <item type="string" name="hideybar_confirmation_message">@string/hideybar_confirmation_message_long</item>
+ <item type="string" name="hiding_navigation_confirmation_message">@string/hiding_navigation_confirmation_message_long</item>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b99d20c..0073e60 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -502,8 +502,8 @@
<string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</string>
<!-- Toast bar message when hiding the navigation bar -->
- <string name="hideybar_confirmation_message">Swipe edge of screen to reveal bar</string>
+ <string name="hiding_navigation_confirmation_message">Swipe edge of screen to reveal bar</string>
<!-- Longer version of toast bar message when hiding the navigation bar (if room) -->
- <string name="hideybar_confirmation_message_long">Swipe from edge of screen to reveal system bar</string>
+ <string name="hiding_navigation_confirmation_message_long">Swipe from edge of screen to reveal system bar</string>
</resources>
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.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 @@
}
};
- private final Stats mStats;
+ private final CpuTracker mStats;
private Paint mLoadPaint;
private Paint mAddedPaint;
@@ -150,7 +150,7 @@
float descent = mLoadPaint.descent();
mFH = (int)(descent - mAscent + .5f);
- mStats = new Stats(mLoadPaint);
+ mStats = new CpuTracker(mLoadPaint);
mStats.init();
updateDisplay();
}
@@ -179,7 +179,7 @@
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 @@
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 @@
}
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/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d1ccde1..3a81454 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -127,11 +127,15 @@
private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
- private static final int STATUS_OR_NAV_OVERLAY =
- View.STATUS_BAR_OVERLAY | View.NAVIGATION_BAR_OVERLAY;
+ private static final int STATUS_OR_NAV_TRANSIENT =
+ View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
private static final long AUTOHIDE_TIMEOUT_MS = 3000;
private static final float TRANSPARENT_ALPHA = 0.7f;
+ private static final int BAR_MODE_NORMAL = 0;
+ private static final int BAR_MODE_TRANSIENT = 1;
+ private static final int BAR_MODE_TRANSPARENT = 2;
+
// fling gesture tuning parameters, scaled to display density
private float mSelfExpandVelocityPx; // classic value: 2000px/s
private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
@@ -306,33 +310,33 @@
}
};
- private Toast mHideybarConfirmation;
- private boolean mHideybarConfirmationDismissed;
+ private Toast mHidingNavigationConfirmation;
+ private boolean mHidingNavigationConfirmationDismissed;
- private final View.OnTouchListener mDismissHideybarConfirmationOnTouchOutside =
+ private final View.OnTouchListener mDismissHidingNavigationConfirmationOnTouchOutside =
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) {
- dismissHideybarConfirmation();
+ dismissHidingNavigationConfirmation();
}
return false;
}
};
- private final Runnable mHideybarConfirmationAction = new Runnable() {
+ private final Runnable mHidingNavigationConfirmationAction = new Runnable() {
@Override
public void run() {
- if (mHideybarConfirmation != null) {
+ if (mHidingNavigationConfirmation != null) {
final boolean isGloballyConfirmed = Prefs.read(mContext)
- .getBoolean(Prefs.HIDEYBAR_CONFIRMED, false);
+ .getBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, false);
if (!isGloballyConfirmed) {
// user pressed button, consider this a confirmation
Prefs.edit(mContext)
- .putBoolean(Prefs.HIDEYBAR_CONFIRMED, true)
+ .putBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, true)
.apply();
}
- dismissHideybarConfirmation();
+ dismissHidingNavigationConfirmation();
}
}
};
@@ -342,7 +346,7 @@
private final Runnable mAutohide = new Runnable() {
@Override
public void run() {
- int requested = mSystemUiVisibility & ~STATUS_OR_NAV_OVERLAY;
+ int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
if (mSystemUiVisibility != requested) {
notifyUiVisibilityChanged(requested);
}
@@ -1892,8 +1896,9 @@
if (diff != 0) {
mSystemUiVisibility = newVal;
- if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) {
- final boolean lightsOut = (0 != (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE));
+ // update low profile
+ if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+ final boolean lightsOut = (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0;
if (lightsOut) {
animateCollapsePanels();
if (mTicking) {
@@ -1908,70 +1913,93 @@
setStatusBarLowProfile(lightsOut);
}
- boolean sbOverlayChanged = 0 != (diff & View.STATUS_BAR_OVERLAY);
- boolean nbOverlayChanged = 0 != (diff & View.NAVIGATION_BAR_OVERLAY);
- if (sbOverlayChanged || nbOverlayChanged) {
- boolean sbOverlay = 0 != (vis & View.STATUS_BAR_OVERLAY);
- boolean nbOverlay = 0 != (vis & View.NAVIGATION_BAR_OVERLAY);
- if (sbOverlayChanged) {
- setTransparent(mStatusBarView, sbOverlay);
- }
- if (nbOverlayChanged) {
- setTransparent(mNavigationBarView, nbOverlay);
- }
- if (sbOverlayChanged && sbOverlay || nbOverlayChanged && nbOverlay) {
+ // update status bar mode
+ int sbMode = updateBarMode(oldVal, newVal, mStatusBarView,
+ View.STATUS_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS);
+
+ // update navigation bar mode
+ int nbMode = updateBarMode(oldVal, newVal, mNavigationBarView,
+ View.NAVIGATION_BAR_TRANSIENT, View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION);
+
+ if (sbMode != -1 || nbMode != -1) {
+ // update transient bar autohide
+ if (sbMode == BAR_MODE_TRANSIENT || nbMode == BAR_MODE_TRANSIENT) {
scheduleAutohide();
} else {
cancelAutohide();
}
}
+
+ // update hiding navigation confirmation
if (mNavigationBarView != null) {
- int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_OVERLAY;
- boolean oldVisible = (oldVal & flags) == flags;
- boolean newVisible = (newVal & flags) == flags;
- if (!oldVisible && newVisible) {
- mHideybarConfirmationDismissed = false;
+ final int hidingNav =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT;
+ boolean oldHidingNav = (oldVal & hidingNav) != 0;
+ boolean newHidingNav = (newVal & hidingNav) != 0;
+ if (!oldHidingNav && newHidingNav) {
+ mHidingNavigationConfirmationDismissed = false;
}
- setHideybarConfirmationVisible(newVisible);
+ setHidingNavigationConfirmationVisible(newHidingNav);
}
+
+ // send updated sysui visibility to window manager
notifyUiVisibilityChanged(mSystemUiVisibility);
}
}
- private void dismissHideybarConfirmation() {
- if (mHideybarConfirmation != null) {
- mHideybarConfirmationDismissed = true;
- mHideybarConfirmation.cancel();
- mHideybarConfirmation = null;
+ private int updateBarMode(int oldVis, int newVis, View view,
+ int transientFlag, int transparentFlag) {
+ final int oldMode = barMode(oldVis, transientFlag, transparentFlag);
+ final int newMode = barMode(newVis, transientFlag, transparentFlag);
+ if (oldMode == newMode) {
+ return -1; // no mode change
+ }
+ setTransparent(view, newMode != BAR_MODE_NORMAL);
+ return newMode;
+ }
+
+ private int barMode(int vis, int transientFlag, int transparentFlag) {
+ return (vis & transientFlag) != 0 ? BAR_MODE_TRANSIENT
+ : (vis & transparentFlag) != 0 ? BAR_MODE_TRANSPARENT
+ : BAR_MODE_NORMAL;
+ }
+
+ private void dismissHidingNavigationConfirmation() {
+ if (mHidingNavigationConfirmation != null) {
+ mHidingNavigationConfirmationDismissed = true;
+ mHidingNavigationConfirmation.cancel();
+ mHidingNavigationConfirmation = null;
}
}
- private void setHideybarConfirmationVisible(boolean visible) {
- if (DEBUG) Log.d(TAG, "setHideybarConfirmationVisible " + visible);
- if (visible && mHideybarConfirmation == null && !mHideybarConfirmationDismissed) {
+ private void setHidingNavigationConfirmationVisible(boolean visible) {
+ if (DEBUG) Log.d(TAG, "setHidingNavigationConfirmationVisible " + visible);
+ if (visible &&
+ mHidingNavigationConfirmation == null && !mHidingNavigationConfirmationDismissed) {
// create the confirmation toast bar
- int msg = R.string.hideybar_confirmation_message;
- mHideybarConfirmation = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE)
- .setAction(com.android.internal.R.string.ok, mHideybarConfirmationAction);
- View v = mHideybarConfirmation.getView();
+ int msg = R.string.hiding_navigation_confirmation_message;
+ mHidingNavigationConfirmation = Toast.makeBar(mContext, msg, Toast.LENGTH_INFINITE)
+ .setAction(com.android.internal.R.string.ok,
+ mHidingNavigationConfirmationAction);
+ View v = mHidingNavigationConfirmation.getView();
v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
boolean isGloballyConfirmed = Prefs.read(mContext)
- .getBoolean(Prefs.HIDEYBAR_CONFIRMED, false);
+ .getBoolean(Prefs.HIDING_NAVIGATION_CONFIRMED, false);
if (isGloballyConfirmed) {
// dismiss on outside touch if globally confirmed
- v.setOnTouchListener(mDismissHideybarConfirmationOnTouchOutside);
+ v.setOnTouchListener(mDismissHidingNavigationConfirmationOnTouchOutside);
}
// position at the bottom like normal toasts, but use top gravity
// to avoid jumping around when showing/hiding the nav bar
v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int offsetY = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.toast_y_offset);
- mHideybarConfirmation.setGravity(Gravity.TOP,
+ mHidingNavigationConfirmation.setGravity(Gravity.TOP,
0, mCurrentDisplaySize.y - v.getMeasuredHeight() / 2 - offsetY);
// show the confirmation
- mHideybarConfirmation.show();
+ mHidingNavigationConfirmation.show();
} else if (!visible) {
- dismissHideybarConfirmation();
+ dismissHidingNavigationConfirmation();
}
}
@@ -1985,7 +2013,7 @@
@Override
public void suspendAutohide() {
mHandler.removeCallbacks(mAutohide);
- mAutohideSuspended = 0 != (mSystemUiVisibility & STATUS_OR_NAV_OVERLAY);
+ mAutohideSuspended = 0 != (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT);
}
private void cancelAutohide() {
@@ -1999,7 +2027,7 @@
}
private void checkUserAutohide(View v, MotionEvent event) {
- if ((mSystemUiVisibility & STATUS_OR_NAV_OVERLAY) != 0 // an overlay bar is revealed
+ if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
&& event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
&& event.getX() == 0 && event.getY() == 0 // a touch outside both bars
) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
index d03f6ce..3d51f20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
@@ -25,7 +25,7 @@
public static final String SHOWN_COMPAT_MODE_HELP = "shown_compat_mode_help";
public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help";
- public static final String HIDEYBAR_CONFIRMED = "hideybar_confirmed";
+ public static final String HIDING_NAVIGATION_CONFIRMED = "hiding_navigation_confirmed";
public static SharedPreferences read(Context context) {
return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 2dfe6af..f83b017 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -164,7 +164,10 @@
* of the screen to change.
*/
static final int SYSTEM_UI_CHANGING_LAYOUT =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS
+ | View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION;
/**
* Keyguard stuff
@@ -526,7 +529,7 @@
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
- OverlayTesting.ENABLED_SETTING), false, this,
+ ImmersiveModeTesting.ENABLED_SETTING), false, this,
UserHandle.USER_ALL);
updateSettings();
}
@@ -550,11 +553,11 @@
}
MyOrientationListener mOrientationListener;
- private static final int HIDEYBAR_NONE = 0;
- private static final int HIDEYBAR_SHOWING = 1;
- private static final int HIDEYBAR_HIDING = 2;
- private int mStatusHideybar;
- private int mNavigationHideybar;
+ private static final int TRANSIENT_BAR_NONE = 0;
+ private static final int TRANSIENT_BAR_SHOWING = 1;
+ private static final int TRANSIENT_BAR_HIDING = 2;
+ private int mStatusTransientBar;
+ private int mNavigationTransientBar;
private SystemGesturesPointerEventListener mSystemGestures;
@@ -917,25 +920,25 @@
@Override
public void onSwipeFromTop() {
if (mStatusBar != null) {
- requestHideybars(mStatusBar);
+ requestTransientBars(mStatusBar);
}
}
@Override
public void onSwipeFromBottom() {
if (mNavigationBar != null && mNavigationBarOnBottom) {
- requestHideybars(mNavigationBar);
+ requestTransientBars(mNavigationBar);
}
}
@Override
public void onSwipeFromRight() {
if (mNavigationBar != null && !mNavigationBarOnBottom) {
- requestHideybars(mNavigationBar);
+ requestTransientBars(mNavigationBar);
}
}
@Override
public void onDebug() {
- if (OverlayTesting.enabled) {
- OverlayTesting.toggleForceOverlay(mFocusedWindow, mContext);
+ if (ImmersiveModeTesting.enabled) {
+ ImmersiveModeTesting.toggleForceImmersiveMode(mFocusedWindow, mContext);
}
}
});
@@ -1152,8 +1155,8 @@
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
- OverlayTesting.enabled = Settings.System.getIntForUser(resolver,
- OverlayTesting.ENABLED_SETTING, 0, UserHandle.USER_CURRENT) != 0;
+ ImmersiveModeTesting.enabled = Settings.System.getIntForUser(resolver,
+ ImmersiveModeTesting.ENABLED_SETTING, 0, UserHandle.USER_CURRENT) != 0;
}
if (updateRotation) {
updateRotation(true);
@@ -2541,14 +2544,14 @@
@Override
public int adjustSystemUiVisibilityLw(int visibility) {
- if (mStatusBar != null && mStatusHideybar == HIDEYBAR_SHOWING &&
- 0 == (visibility & View.STATUS_BAR_OVERLAY)) {
- mStatusHideybar = HIDEYBAR_HIDING;
+ if (mStatusBar != null && mStatusTransientBar == TRANSIENT_BAR_SHOWING &&
+ 0 == (visibility & View.STATUS_BAR_TRANSIENT)) {
+ mStatusTransientBar = TRANSIENT_BAR_HIDING;
setBarShowingLw(mStatusBar, false);
}
- if (mNavigationBar != null && mNavigationHideybar == HIDEYBAR_SHOWING &&
- 0 == (visibility & View.NAVIGATION_BAR_OVERLAY)) {
- mNavigationHideybar = HIDEYBAR_HIDING;
+ if (mNavigationBar != null && mNavigationTransientBar == TRANSIENT_BAR_SHOWING &&
+ 0 == (visibility & View.NAVIGATION_BAR_TRANSIENT)) {
+ mNavigationTransientBar = TRANSIENT_BAR_HIDING;
setBarShowingLw(mNavigationBar, false);
}
// Reset any bits in mForceClearingStatusBarVisibility that
@@ -2678,14 +2681,17 @@
if (isDefaultDisplay) {
// For purposes of putting out fake window up to steal focus, we will
// drive nav being hidden only by whether it is requested.
- boolean navVisible = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
- boolean overlayAllowed = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_ALLOW_OVERLAY) != 0;
+ final int sysui = mLastSystemUiFlags;
+ boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+ boolean navTransparent = (sysui & View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION) != 0;
+ boolean transientAllowed = (sysui & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0;
+ navTransparent &= !transientAllowed; // transient trumps transparent
// When the navigation bar isn't visible, we put up a fake
// input window to catch all touch events. This way we can
// detect when the user presses anywhere to bring back the nav
// bar and ensure the application doesn't see the event.
- if (navVisible || overlayAllowed) {
+ if (navVisible || transientAllowed) {
if (mHideNavFakeWindow != null) {
mHideNavFakeWindow.dismiss();
mHideNavFakeWindow = null;
@@ -2704,7 +2710,7 @@
boolean updateSysUiVisibility = false;
if (mNavigationBar != null) {
- boolean navBarHideyShowing = mNavigationHideybar == HIDEYBAR_SHOWING;
+ boolean transientNavBarShowing = mNavigationTransientBar == TRANSIENT_BAR_SHOWING;
// Force the navigation bar to its appropriate place and
// size. We need to do this directly, instead of relying on
// it to bubble up from the nav bar, because this needs to
@@ -2716,7 +2722,7 @@
- mNavigationBarHeightForRotation[displayRotation];
mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
- if (navBarHideyShowing) {
+ if (transientNavBarShowing || navTransparent) {
setBarShowingLw(mNavigationBar, true);
} else if (navVisible) {
setBarShowingLw(mNavigationBar, true);
@@ -2727,8 +2733,8 @@
// We currently want to hide the navigation UI.
setBarShowingLw(mNavigationBar, false);
}
- if (navVisible && !mNavigationBar.isAnimatingLw()) {
- // If the nav bar is currently requested to be visible,
+ if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()) {
+ // If the opaque nav bar is currently requested to be visible,
// and not in the process of animating on or off, then
// we can tell the app that it is covered by it.
mSystemBottom = mTmpNavigationFrame.top;
@@ -2739,7 +2745,7 @@
- mNavigationBarWidthForRotation[displayRotation];
mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
- if (navBarHideyShowing) {
+ if (transientNavBarShowing || navTransparent) {
setBarShowingLw(mNavigationBar, true);
} else if (navVisible) {
setBarShowingLw(mNavigationBar, true);
@@ -2750,7 +2756,7 @@
// We currently want to hide the navigation UI.
setBarShowingLw(mNavigationBar, false);
}
- if (navVisible && !mNavigationBar.isAnimatingLw()) {
+ if (navVisible && !navTransparent && !mNavigationBar.isAnimatingLw()) {
// If the nav bar is currently requested to be visible,
// and not in the process of animating on or off, then
// we can tell the app that it is covered by it.
@@ -2768,9 +2774,9 @@
mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame);
if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
- if (mNavigationHideybar == HIDEYBAR_HIDING && !mNavigationBar.isVisibleLw()) {
+ if (mNavigationTransientBar == TRANSIENT_BAR_HIDING && !mNavigationBar.isVisibleLw()) {
// Finished animating out, clean up and reset alpha
- mNavigationHideybar = HIDEYBAR_NONE;
+ mNavigationTransientBar = TRANSIENT_BAR_NONE;
updateSysUiVisibility = true;
}
}
@@ -2798,11 +2804,12 @@
// For layout, the status bar is always at the top with our fixed height.
mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
- boolean statusBarOverlay = (mLastSystemUiFlags & View.STATUS_BAR_OVERLAY) != 0;
+ boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+ boolean statusBarTransparent = (sysui & View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS) != 0;
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarOverlay) {
+ if (mStatusBar.isVisibleLw() && !statusBarTransient && !statusBarTransparent) {
// Status bar may go away, so the screen area it occupies
// is available to apps but just covering them when the
// status bar is visible.
@@ -2820,16 +2827,17 @@
mContentLeft, mContentTop, mContentRight, mContentBottom,
mCurLeft, mCurTop, mCurRight, mCurBottom));
}
- if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw() && !statusBarOverlay) {
- // If the status bar is currently requested to be visible,
+ if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()
+ && !statusBarTransient && !statusBarTransparent) {
+ // If the opaque status bar is currently requested to be visible,
// and not in the process of animating on or off, then
// we can tell the app that it is covered by it.
mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
}
- if (mStatusHideybar == HIDEYBAR_HIDING && !mStatusBar.isVisibleLw()) {
+ if (mStatusTransientBar == TRANSIENT_BAR_HIDING && !mStatusBar.isVisibleLw()) {
// Finished animating out, clean up and reset alpha
- mStatusHideybar = HIDEYBAR_NONE;
+ mStatusTransientBar = TRANSIENT_BAR_NONE;
updateSysUiVisibility = true;
}
}
@@ -3411,7 +3419,7 @@
// and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
// has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
// case though.
- if (mStatusHideybar == HIDEYBAR_SHOWING) {
+ if (mStatusTransientBar == TRANSIENT_BAR_SHOWING) {
if (setBarShowingLw(mStatusBar, true)) {
changes |= FINISH_LAYOUT_REDO_LAYOUT;
}
@@ -4135,32 +4143,32 @@
}
};
- private void requestHideybars(WindowState swipeTarget) {
+ private void requestTransientBars(WindowState swipeTarget) {
synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- boolean sb = checkShowHideybar("status", mStatusHideybar, mStatusBar);
- boolean nb = checkShowHideybar("navigation", mNavigationHideybar, mNavigationBar);
+ boolean sb = checkShowTransientBar("status", mStatusTransientBar, mStatusBar);
+ boolean nb = checkShowTransientBar("nav", mNavigationTransientBar, mNavigationBar);
if (sb || nb) {
- WindowState hideyTarget = sb ? mStatusBar : mNavigationBar;
- if (sb ^ nb && hideyTarget != swipeTarget) {
- if (DEBUG) Slog.d(TAG, "Not showing hideybar, wrong swipe target");
+ WindowState barTarget = sb ? mStatusBar : mNavigationBar;
+ if (sb ^ nb && barTarget != swipeTarget) {
+ if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
return;
}
- mStatusHideybar = sb ? HIDEYBAR_SHOWING : mStatusHideybar;
- mNavigationHideybar = nb ? HIDEYBAR_SHOWING : mNavigationHideybar;
+ mStatusTransientBar = sb ? TRANSIENT_BAR_SHOWING : mStatusTransientBar;
+ mNavigationTransientBar = nb ? TRANSIENT_BAR_SHOWING : mNavigationTransientBar;
updateSystemUiVisibilityLw();
}
}
}
- private boolean checkShowHideybar(String tag, int hideybar, WindowState win) {
- if (hideybar == HIDEYBAR_SHOWING) {
- if (DEBUG) Slog.d(TAG, "Not showing " + tag + " hideybar, already shown");
+ private boolean checkShowTransientBar(String tag, int transientBar, WindowState win) {
+ if (transientBar == TRANSIENT_BAR_SHOWING) {
+ if (DEBUG) Slog.d(TAG, "Not showing " + tag + " transient bar, already shown");
return false;
} else if (win == null) {
- if (DEBUG) Slog.d(TAG, "Not showing " + tag + " hideybar, bar doesn't exist");
+ if (DEBUG) Slog.d(TAG, "Not showing " + tag + " transient bar, bar doesn't exist");
return false;
} else if (win.isDisplayedLw()) {
- if (DEBUG) Slog.d(TAG, "Not showing " + tag + " hideybar, bar already visible");
+ if (DEBUG) Slog.d(TAG, "Not showing " + tag + " transient bar, bar already visible");
return false;
} else {
return true;
@@ -5009,7 +5017,7 @@
if (mForcingShowNavBar && mFocusedWindow.getSurfaceLayer() < mForcingShowNavBarLayer) {
tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
}
- final int visibility = updateHideybarsLw(tmpVisibility);
+ final int visibility = updateTransientBarsLw(tmpVisibility);
final int diff = visibility ^ mLastSystemUiFlags;
final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
if (diff == 0 && mLastFocusNeedsMenu == needsMenu
@@ -5037,35 +5045,34 @@
return diff;
}
- private int updateHideybarsLw(int tmpVisibility) {
- if (OverlayTesting.enabled) {
- tmpVisibility = OverlayTesting.applyForced(mFocusedWindow, tmpVisibility);
+ private int updateTransientBarsLw(int vis) {
+ if (ImmersiveModeTesting.enabled) {
+ vis = ImmersiveModeTesting.applyForced(mFocusedWindow, vis);
}
- boolean statusBarHasFocus =
- mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
+ boolean statusBarHasFocus = mFocusedWindow.getAttrs().type == TYPE_STATUS_BAR;
if (statusBarHasFocus) {
// prevent status bar interaction from clearing certain flags
int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_ALLOW_OVERLAY;
- tmpVisibility = (tmpVisibility & ~flags) | (mLastSystemUiFlags & flags);
+ | View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT;
+ vis = (vis & ~flags) | (mLastSystemUiFlags & flags);
}
- boolean overlayAllowed = (tmpVisibility & View.SYSTEM_UI_FLAG_ALLOW_OVERLAY) != 0;
- if (mStatusHideybar == HIDEYBAR_SHOWING) {
- // status hideybar requested
+ boolean transientAllowed = (vis & View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT) != 0;
+ if (mStatusTransientBar == TRANSIENT_BAR_SHOWING) {
+ // status transient bar requested
boolean hideStatusBarWM =
(mFocusedWindow.getAttrs().flags
& WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
boolean hideStatusBarSysui =
- (tmpVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+ (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
- boolean statusHideyAllowed =
+ boolean transientStatusBarAllowed =
hideStatusBarWM
- || (hideStatusBarSysui && overlayAllowed)
+ || (hideStatusBarSysui && transientAllowed)
|| statusBarHasFocus;
- if (mStatusBar == null || !statusHideyAllowed) {
- mStatusHideybar = HIDEYBAR_NONE;
+ if (mStatusBar == null || !transientStatusBarAllowed) {
+ mStatusTransientBar = TRANSIENT_BAR_NONE;
if (mStatusBar != null && hideStatusBarSysui) {
// clear the clearable flags instead
int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
@@ -5075,32 +5082,32 @@
}
}
} else {
- // show status hideybar
- tmpVisibility |= View.STATUS_BAR_OVERLAY;
- if ((mLastSystemUiFlags & View.STATUS_BAR_OVERLAY) == 0) {
- tmpVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ // show status transient bar
+ vis |= View.STATUS_BAR_TRANSIENT;
+ if ((mLastSystemUiFlags & View.STATUS_BAR_TRANSIENT) == 0) {
+ vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
setBarShowingLw(mStatusBar, true);
}
}
}
- if (mNavigationHideybar == HIDEYBAR_SHOWING) {
- // navigation hideybar requested
+ if (mNavigationTransientBar == TRANSIENT_BAR_SHOWING) {
+ // navigation transient bar requested
boolean hideNavigationBarSysui =
- (tmpVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
- boolean navigationHideyAllowed =
- hideNavigationBarSysui && overlayAllowed && mNavigationBar != null;
- if (!navigationHideyAllowed) {
- mNavigationHideybar = HIDEYBAR_NONE;
+ (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+ boolean transientNavigationBarAllowed =
+ mNavigationBar != null && hideNavigationBarSysui && transientAllowed;
+ if (!transientNavigationBarAllowed) {
+ mNavigationTransientBar = TRANSIENT_BAR_NONE;
} else {
- // show navigation hideybar
- tmpVisibility |= View.NAVIGATION_BAR_OVERLAY;
- if ((mLastSystemUiFlags & View.NAVIGATION_BAR_OVERLAY) == 0) {
- tmpVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ // show navigation transient bar
+ vis |= View.NAVIGATION_BAR_TRANSIENT;
+ if ((mLastSystemUiFlags & View.NAVIGATION_BAR_TRANSIENT) == 0) {
+ vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
setBarShowingLw(mNavigationBar, true);
}
}
}
- return tmpVisibility;
+ return vis;
}
private boolean setBarShowingLw(WindowState win, final boolean show) {
@@ -5129,9 +5136,10 @@
return show ? win.showLw(true) : win.hideLw(true);
}
- // TODO temporary helper that allows testing overlay bars on existing apps
- private static final class OverlayTesting {
- static String ENABLED_SETTING = "overlay_testing_enabled";
+ // Temporary helper that allows testing immersive mode on existing apps
+ // TODO remove
+ private static final class ImmersiveModeTesting {
+ static String ENABLED_SETTING = "immersive_mode_testing_enabled";
static boolean enabled = false;
private static final HashSet<String> sForced = new HashSet<String>();
@@ -5153,21 +5161,21 @@
if (sForced.contains(parseActivity(focused))) {
vis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
- View.SYSTEM_UI_FLAG_ALLOW_OVERLAY;
+ View.SYSTEM_UI_FLAG_ALLOW_TRANSIENT;
}
return vis;
}
- public static void toggleForceOverlay(WindowState focused, Context context) {
+ public static void toggleForceImmersiveMode(WindowState focused, Context context) {
String activity = parseActivity(focused);
if (activity != null) {
String action;
if (sForced.contains(activity)) {
sForced.remove(activity);
- action = "Force overlay disabled";
+ action = "Force immersive mode disabled";
} else {
sForced.add(activity);
- action = "Force overlay enabled";
+ action = "Force immersive mode enabled";
}
android.widget.Toast.makeText(context,
action + " for " + activity, android.widget.Toast.LENGTH_SHORT).show();
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.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 @@
}
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
((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 @@
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 @@
}
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 @@
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 @@
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 @@
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 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 @@
* 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 @@
= 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 @@
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 @@
return;
}
- mActivityManagerService.mProcessTracker.dump(fd, pw, args);
+ mActivityManagerService.mProcessStats.dump(fd, pw, args);
}
}
@@ -1795,7 +1796,7 @@
: 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 @@
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 @@
nextCpuDelay = nextWriteDelay;
}
if (nextCpuDelay > 0) {
- mProcessStatsMutexFree.set(true);
+ mProcessCpuMutexFree.set(true);
this.wait(nextCpuDelay);
}
}
@@ -1852,7 +1853,7 @@
}
}
};
- mProcessStatsThread.start();
+ mProcessCpuThread.start();
}
@Override
@@ -1902,16 +1903,16 @@
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 @@
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 @@
}
}
- long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
+ long[] cpuSpeedTimes = mProcessCpuTracker.getLastCpuSpeedTimes();
final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
synchronized(bstats) {
synchronized(mPidsSelfLocked) {
@@ -1955,9 +1956,9 @@
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 @@
// 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 @@
}
} 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 @@
* @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 @@
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 @@
}
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
mUsageStatsService.shutdown();
mBatteryStatsService.shutdown();
synchronized (this) {
- mProcessTracker.shutdownLocked();
+ mProcessStats.shutdownLocked();
}
return timedout;
@@ -11665,7 +11666,7 @@
app.crashing = false;
app.notResponding = false;
- app.resetPackageList(mProcessTracker);
+ app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
app.thread = null;
app.forcingToForeground = null;
@@ -14540,7 +14541,7 @@
+ " 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 @@
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 @@
}
}
} 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 @@
}
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..a0bbfad 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -177,6 +177,13 @@
ActivityRecord mLastPausedActivity = null;
/**
+ * Activities that specify No History must be removed once the user navigates away from them.
+ * If the device goes to sleep with such an activity in the paused state then we save it here
+ * and finish it later if another activity replaces it on wakeup.
+ */
+ ActivityRecord mLastNoHistoryActivity = null;
+
+ /**
* Current activity that is resumed, or null if there is none.
*/
ActivityRecord mResumedActivity = null;
@@ -710,6 +717,8 @@
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
+ mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
+ || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
clearLaunchTime(prev);
@@ -732,10 +741,12 @@
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
+ mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
+ mLastNoHistoryActivity = null;
}
// If we are not going to sleep, we want to ensure the device is
@@ -893,8 +904,8 @@
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 +913,7 @@
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 +946,8 @@
// 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
@@ -1333,16 +1344,13 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- final ActivityRecord last = mLastPausedActivity;
- if (mService.mSleeping && last != null && !last.finishing) {
- if ((last.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
- || (last.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
- if (DEBUG_STATES) {
- Slog.d(TAG, "no-history finish of " + last + " on new resume");
- }
- requestFinishActivityLocked(last.appToken, Activity.RESULT_CANCELED, null,
- "no-history", false);
- }
+ if (mService.mSleeping && mLastNoHistoryActivity != null &&
+ !mLastNoHistoryActivity.finishing) {
+ if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity +
+ " on new resume");
+ requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
+ null, "no-history", false);
+ mLastNoHistoryActivity = null;
}
if (prev != null && prev != next) {
@@ -2949,7 +2957,6 @@
mWindowManager.moveTaskToTop(tr.taskId);
- mLastPausedActivity = null;
mStackSupervisor.resumeTopActivitiesLocked();
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
@@ -3368,6 +3375,7 @@
}
if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
mLastPausedActivity = null;
+ mLastNoHistoryActivity = null;
}
final ActivityRecord top = topRunningActivityLocked(null);
final boolean launchHomeTaskNext =
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 1681c2d..467c0b3 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1027,7 +1027,7 @@
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) {
@@ -1398,6 +1398,7 @@
r.task = intentActivity.task;
}
targetStack = intentActivity.task.stack;
+ targetStack.mLastPausedActivity = null;
moveHomeStack(targetStack.isHomeStack());
if (intentActivity.task.intent == null) {
// This task was started because of movement of
@@ -1575,6 +1576,7 @@
top.task);
// For paranoia, make sure we have correctly
// resumed the top activity.
+ topStack.mLastPausedActivity = null;
if (doResume) {
setLaunchHomeTaskNextFlag(sourceRecord, null, topStack);
resumeTopActivitiesLocked();
@@ -1653,6 +1655,7 @@
top.deliverNewIntentLocked(callingUid, r.intent);
// For paranoia, make sure we have correctly
// resumed the top activity.
+ targetStack.mLastPausedActivity = null;
if (doResume) {
setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
targetStack.resumeTopActivityLocked(null);
@@ -1675,6 +1678,7 @@
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
top.updateOptionsLocked(options);
top.deliverNewIntentLocked(callingUid, r.intent);
+ targetStack.mLastPausedActivity = null;
if (doResume) {
setLaunchHomeTaskNextFlag(sourceRecord, null, targetStack);
targetStack.resumeTopActivityLocked(null);
@@ -1714,6 +1718,7 @@
}
ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
setLaunchHomeTaskNextFlag(sourceRecord, r, targetStack);
+ targetStack.mLastPausedActivity = null;
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
mService.setFocusedActivityLocked(r);
return ActivityManager.START_SUCCESS;
@@ -2390,7 +2395,10 @@
" mLastPausedActivity: ");
if (pr) {
printed = true;
+ needSep = true;
}
+ printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
+ needSep, " mLastNoHistoryActivity: ");
}
needSep = printed;
}
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 @@
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 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 @@
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 @@
/*
* 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 @@
/*
* 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 @@
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 @@
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;
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index 4496aae..ab4ac04 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -48,9 +48,8 @@
public class IntentFirewall {
private static final String TAG = "IntentFirewall";
- // e.g. /data/system/ifw/ifw.xml or /data/secure/system/ifw/ifw.xml
- private static final File RULES_FILE =
- new File(Environment.getSystemSecureDirectory(), "ifw/ifw.xml");
+ // e.g. /data/system/ifw or /data/secure/system/ifw
+ private static final File RULES_DIR = new File(Environment.getSystemSecureDirectory(), "ifw");
private static final int LOG_PACKAGES_MAX_LENGTH = 150;
private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
@@ -106,12 +105,12 @@
public IntentFirewall(AMSInterface ams) {
mAms = ams;
- File rulesFile = getRulesFile();
- rulesFile.getParentFile().mkdirs();
+ File rulesDir = getRulesDir();
+ rulesDir.mkdirs();
- readRules(rulesFile);
+ readRulesDir(rulesDir);
- mObserver = new RuleObserver(rulesFile);
+ mObserver = new RuleObserver(rulesDir);
mObserver.startWatching();
}
@@ -216,22 +215,58 @@
return null;
}
- public static File getRulesFile() {
- return RULES_FILE;
+ public static File getRulesDir() {
+ return RULES_DIR;
}
/**
- * Reads rules from the given file and replaces our set of rules with the newly read rules
+ * Reads rules from all xml files (*.xml) in the given directory, and replaces our set of rules
+ * with the newly read rules.
+ *
+ * We only check for files ending in ".xml", to allow for temporary files that are atomically
+ * renamed to .xml
*
* All calls to this method from the file observer come through a handler and are inherently
* serialized
*/
- private void readRules(File rulesFile) {
+ private void readRulesDir(File rulesDir) {
FirewallIntentResolver[] resolvers = new FirewallIntentResolver[3];
for (int i=0; i<resolvers.length; i++) {
resolvers[i] = new FirewallIntentResolver();
}
+ File[] files = rulesDir.listFiles();
+ for (int i=0; i<files.length; i++) {
+ File file = files[i];
+
+ if (file.getName().endsWith(".xml")) {
+ readRules(file, resolvers);
+ }
+ }
+
+ Slog.i(TAG, "Read new rules (A:" + resolvers[TYPE_ACTIVITY].filterSet().size() +
+ " B:" + resolvers[TYPE_BROADCAST].filterSet().size() +
+ " S:" + resolvers[TYPE_SERVICE].filterSet().size() + ")");
+
+ synchronized (mAms.getAMSLock()) {
+ mActivityResolver = resolvers[TYPE_ACTIVITY];
+ mBroadcastResolver = resolvers[TYPE_BROADCAST];
+ mServiceResolver = resolvers[TYPE_SERVICE];
+ }
+ }
+
+ /**
+ * Reads rules from the given file and add them to the given resolvers
+ */
+ private void readRules(File rulesFile, FirewallIntentResolver[] resolvers) {
+ // some temporary lists to hold the rules while we parse the xml file, so that we can
+ // add the rules all at once, after we know there weren't any major structural problems
+ // with the xml file
+ List<List<Rule>> rulesByType = new ArrayList<List<Rule>>(3);
+ for (int i=0; i<3; i++) {
+ rulesByType.add(new ArrayList<Rule>());
+ }
+
FileInputStream fis;
try {
fis = new FileInputStream(rulesFile);
@@ -247,8 +282,6 @@
XmlUtils.beginDocument(parser, TAG_RULES);
- int[] numRules = new int[3];
-
int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
int ruleType = -1;
@@ -265,41 +298,28 @@
if (ruleType != -1) {
Rule rule = new Rule();
- FirewallIntentResolver resolver = resolvers[ruleType];
+ List<Rule> rules = rulesByType.get(ruleType);
// if we get an error while parsing a particular rule, we'll just ignore
// that rule and continue on with the next rule
try {
rule.readFromXml(parser);
} catch (XmlPullParserException ex) {
- Slog.e(TAG, "Error reading intent firewall rule", ex);
+ Slog.e(TAG, "Error reading an intent firewall rule from " + rulesFile, ex);
continue;
}
- numRules[ruleType]++;
-
- for (int i=0; i<rule.getIntentFilterCount(); i++) {
- resolver.addFilter(rule.getIntentFilter(i));
- }
+ rules.add(rule);
}
}
-
- Slog.i(TAG, "Read new rules (A:" + numRules[TYPE_ACTIVITY] +
- " B:" + numRules[TYPE_BROADCAST] + " S:" + numRules[TYPE_SERVICE] + ")");
-
- synchronized (mAms.getAMSLock()) {
- mActivityResolver = resolvers[TYPE_ACTIVITY];
- mBroadcastResolver = resolvers[TYPE_BROADCAST];
- mServiceResolver = resolvers[TYPE_SERVICE];
- }
} catch (XmlPullParserException ex) {
// if there was an error outside of a specific rule, then there are probably
// structural problems with the xml file, and we should completely ignore it
- Slog.e(TAG, "Error reading intent firewall rules", ex);
- clearRules();
+ Slog.e(TAG, "Error reading intent firewall rules from " + rulesFile, ex);
+ return;
} catch (IOException ex) {
- Slog.e(TAG, "Error reading intent firewall rules", ex);
- clearRules();
+ Slog.e(TAG, "Error reading intent firewall rules from " + rulesFile, ex);
+ return;
} finally {
try {
fis.close();
@@ -307,21 +327,17 @@
Slog.e(TAG, "Error while closing " + rulesFile, ex);
}
}
- }
- /**
- * Clears out all of our rules
- *
- * All calls to this method from the file observer come through a handler and are inherently
- * serialized
- */
- private void clearRules() {
- Slog.i(TAG, "Clearing all rules");
+ for (int ruleType=0; ruleType<rulesByType.size(); ruleType++) {
+ List<Rule> rules = rulesByType.get(ruleType);
+ FirewallIntentResolver resolver = resolvers[ruleType];
- synchronized (mAms.getAMSLock()) {
- mActivityResolver = new FirewallIntentResolver();
- mBroadcastResolver = new FirewallIntentResolver();
- mServiceResolver = new FirewallIntentResolver();
+ for (int ruleIndex=0; ruleIndex<rules.size(); ruleIndex++) {
+ Rule rule = rules.get(ruleIndex);
+ for (int filterIndex=0; filterIndex<rule.getIntentFilterCount(); filterIndex++) {
+ resolver.addFilter(rule.getIntentFilter(filterIndex));
+ }
+ }
}
}
@@ -421,54 +437,32 @@
}
}
- private static final int READ_RULES = 0;
- private static final int CLEAR_RULES = 1;
-
final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- switch (msg.what) {
- case READ_RULES:
- readRules(getRulesFile());
- break;
- case CLEAR_RULES:
- clearRules();
- break;
- }
+ readRulesDir(getRulesDir());
}
};
/**
- * Monitors for the creation/deletion/modification of the rule file
+ * Monitors for the creation/deletion/modification of any .xml files in the rule directory
*/
private class RuleObserver extends FileObserver {
- // The file name we're monitoring, with no path component
- private final String mMonitoredFile;
+ private static final int MONITORED_EVENTS = FileObserver.CREATE|FileObserver.MOVED_TO|
+ FileObserver.CLOSE_WRITE|FileObserver.DELETE|FileObserver.MOVED_FROM;
- private static final int CREATED_FLAGS = FileObserver.CREATE|FileObserver.MOVED_TO|
- FileObserver.CLOSE_WRITE;
- private static final int DELETED_FLAGS = FileObserver.DELETE|FileObserver.MOVED_FROM;
-
- public RuleObserver(File monitoredFile) {
- super(monitoredFile.getParentFile().getAbsolutePath(), CREATED_FLAGS|DELETED_FLAGS);
- mMonitoredFile = monitoredFile.getName();
+ public RuleObserver(File monitoredDir) {
+ super(monitoredDir.getAbsolutePath(), MONITORED_EVENTS);
}
@Override
public void onEvent(int event, String path) {
- if (path.equals(mMonitoredFile)) {
+ if (path.endsWith(".xml")) {
// we wait 250ms before taking any action on an event, in order to dedup multiple
// events. E.g. a delete event followed by a create event followed by a subsequent
- // write+close event;
- if ((event & CREATED_FLAGS) != 0) {
- mHandler.removeMessages(READ_RULES);
- mHandler.removeMessages(CLEAR_RULES);
- mHandler.sendEmptyMessageDelayed(READ_RULES, 250);
- } else if ((event & DELETED_FLAGS) != 0) {
- mHandler.removeMessages(READ_RULES);
- mHandler.removeMessages(CLEAR_RULES);
- mHandler.sendEmptyMessageDelayed(CLEAR_RULES, 250);
- }
+ // write+close event
+ mHandler.removeMessages(0);
+ mHandler.sendEmptyMessageDelayed(0, 250);
}
}
}
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
index 9185903..0b54f92 100644
--- a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
+++ b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
@@ -21,7 +21,8 @@
public class IntentFirewallInstallReceiver extends ConfigUpdateInstallReceiver {
public IntentFirewallInstallReceiver() {
- super(IntentFirewall.getRulesFile().getParent(), IntentFirewall.getRulesFile().getName(),
- "metadata/", "version");
+ // TODO: should we dynamically generate a filename and store the name in metadata?
+ super(IntentFirewall.getRulesDir().getAbsolutePath(), "ifw.xml", "metadata/",
+ "gservices.version");
}
}