summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Sandler <dsandler@android.com>2013-06-14 20:17:30 -0400
committerDaniel Sandler <dsandler@android.com>2013-06-21 01:16:27 -0400
commitb9eb2865af05d9ade572e71934a9e6a50421aa7d (patch)
treeff4515d45eff0002b7025ca1838a22be60e084b9
parent211667e4c2efc6b0b7c5037aca77eecd50bd823d (diff)
downloadandroid_packages_apps_Trebuchet-b9eb2865af05d9ade572e71934a9e6a50421aa7d.tar.gz
android_packages_apps_Trebuchet-b9eb2865af05d9ade572e71934a9e6a50421aa7d.tar.bz2
android_packages_apps_Trebuchet-b9eb2865af05d9ade572e71934a9e6a50421aa7d.zip
Memory tracking is now handled by a service.
Multiple processes may be tracked and viewed simultaneously. Also, some changes to the graph: * show uss and pss together * adjust opacity controls Change-Id: I20eebaa8cc8faf78b46af2a35d71ee538207f02b
-rw-r--r--AndroidManifest.xml5
-rw-r--r--src/com/android/launcher3/Launcher.java6
-rw-r--r--src/com/android/launcher3/LauncherAppState.java18
-rw-r--r--src/com/android/launcher3/MemoryDumpActivity.java16
-rw-r--r--src/com/android/launcher3/MemoryTracker.java158
-rw-r--r--src/com/android/launcher3/WeightWatcher.java189
6 files changed, 313 insertions, 79 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index baf6990de..e1ad9f543 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -125,6 +125,11 @@
</intent-filter>
</activity>
+ <service android:name="com.android.launcher3.MemoryTracker"
+ android:enabled="@bool/debug_memory_enabled"
+ >
+ </service>
+
<!-- Intent received used to prepopulate the default workspace. -->
<receiver
android:name="com.android.launcher3.PreloadReceiver"
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0253103ea..be0168261 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1043,10 +1043,12 @@ public class Launcher extends Activity
if (getResources().getBoolean(R.bool.debug_memory_enabled)) {
Log.v(TAG, "adding WeightWatcher");
- ((FrameLayout) mLauncherView).addView(new WeightWatcher(this),
+ final View ww = new WeightWatcher(this);
+ ww.setAlpha(0.5f);
+ ((FrameLayout) mLauncherView).addView(ww,
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
- 44,
+ FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.BOTTOM)
);
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index af9acb152..aeafcf084 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -17,16 +17,15 @@
package com.android.launcher3;
import android.app.SearchManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.*;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Debug;
import android.os.Environment;
import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
import java.io.File;
import java.io.IOException;
@@ -63,10 +62,21 @@ public class LauncherAppState {
private LauncherAppState() { }
private void initialize(Context context) {
+ Log.v(Launcher.TAG, "LauncherAppState initialize() called in process " + android.os.Process.myPid());
+
mContext = context;
mStarttime = System.currentTimeMillis();
+ if (context.getResources().getBoolean(R.bool.debug_memory_enabled)) {
+ context.startService(new Intent(context, MemoryTracker.class)
+ .setAction(MemoryTracker.ACTION_START_TRACKING)
+ .putExtra("pid", android.os.Process.myPid())
+ .putExtra("name", "L")
+ );
+ }
+
+
// set sIsScreenXLarge and sScreenDensity *before* creating icon cache
sIsScreenLarge = context.getResources().getBoolean(R.bool.is_large_screen);
sScreenDensity = context.getResources().getDisplayMetrics().density;
diff --git a/src/com/android/launcher3/MemoryDumpActivity.java b/src/com/android/launcher3/MemoryDumpActivity.java
index 19b1c4ed1..51bc30808 100644
--- a/src/com/android/launcher3/MemoryDumpActivity.java
+++ b/src/com/android/launcher3/MemoryDumpActivity.java
@@ -1,3 +1,19 @@
+/*
+ * 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.launcher3;
import android.app.Activity;
diff --git a/src/com/android/launcher3/MemoryTracker.java b/src/com/android/launcher3/MemoryTracker.java
new file mode 100644
index 000000000..600344e50
--- /dev/null
+++ b/src/com/android/launcher3/MemoryTracker.java
@@ -0,0 +1,158 @@
+/*
+ * 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.launcher3;
+
+import android.app.ActivityManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.*;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+import java.util.ArrayList;
+
+public class MemoryTracker extends Service {
+ public static final String TAG = MemoryTracker.class.getSimpleName();
+ public static final String ACTION_START_TRACKING = "com.android.launcher3.action.START_TRACKING";
+
+ private static final long UPDATE_RATE = 5000;
+
+ private static final int MSG_START = 1;
+ private static final int MSG_STOP = 2;
+ private static final int MSG_UPDATE = 3;
+
+ public static class ProcessMemInfo {
+ public int pid;
+ public String name;
+ public long currentPss, currentUss;
+ public long[] pss = new long[256];
+ public long[] uss = new long[256];
+ //= new Meminfo[(int) (30 * 60 / (UPDATE_RATE / 1000))]; // 30 minutes
+ public long max = 1;
+ public int head = 0;
+ public ProcessMemInfo(int pid, String name) {
+ this.pid = pid;
+ this.name = name;
+ }
+ };
+ public final LongSparseArray<ProcessMemInfo> mData = new LongSparseArray<ProcessMemInfo>();
+ public final ArrayList<Long> mPids = new ArrayList<Long>();
+ private int[] mPidsArray = new int[0];
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case MSG_START:
+ mHandler.removeMessages(MSG_UPDATE);
+ mHandler.sendEmptyMessage(MSG_UPDATE);
+ break;
+ case MSG_STOP:
+ mHandler.removeMessages(MSG_UPDATE);
+ break;
+ case MSG_UPDATE:
+ update();
+ mHandler.removeMessages(MSG_UPDATE);
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
+ break;
+ }
+ }
+ };
+
+ ActivityManager mAm;
+
+ public ProcessMemInfo getMemInfo(int pid) {
+ return mData.get(pid);
+ }
+
+ public int[] getTrackedProcesses() {
+ return mPidsArray;
+ }
+
+ public void startTrackingProcess(int pid, String name) {
+ mPids.add(new Long(pid));
+ final int N = mPids.size();
+ mPidsArray = new int[N];
+ StringBuffer sb = new StringBuffer("Now tracking processes: ");
+ for (int i=0; i<N; i++) {
+ final int p = mPids.get(i).intValue();
+ mPidsArray[i] = p;
+ sb.append(p); sb.append(" ");
+ }
+ mData.put(pid, new ProcessMemInfo(pid, name));
+ Log.v(TAG, sb.toString());
+ }
+
+ void update() {
+ Debug.MemoryInfo[] dinfos = mAm.getProcessMemoryInfo(mPidsArray);
+ for (int i=0; i<dinfos.length; i++) {
+ Debug.MemoryInfo dinfo = dinfos[i];
+ final long pid = mPids.get(i).intValue();
+ final ProcessMemInfo info = mData.get(pid);
+ info.head = (info.head+1) % info.pss.length;
+ info.pss[info.head] = info.currentPss = dinfo.getTotalPss();
+ info.uss[info.head] = info.currentUss = dinfo.getTotalPrivateDirty();
+ if (info.currentPss > info.max) info.max = info.currentPss;
+ if (info.currentUss > info.max) info.max = info.currentUss;
+ //Log.v(TAG, "update: pid " + pid + " pss=" + info.currentPss + " uss=" + info.currentUss);
+ }
+
+ // XXX: notify listeners
+ }
+
+ @Override
+ public void onCreate() {
+ mAm = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ }
+
+ @Override
+ public void onDestroy() {
+ mHandler.sendEmptyMessage(MSG_STOP);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i(TAG, "Received start id " + startId + ": " + intent);
+
+ if (ACTION_START_TRACKING.equals(intent.getAction())) {
+ final Uri uri = intent.getData();
+ final int pid = intent.getIntExtra("pid", -1);
+ final String name = intent.getStringExtra("name");
+ startTrackingProcess(pid, name);
+ }
+
+ mHandler.sendEmptyMessage(MSG_START);
+
+ return START_STICKY;
+ }
+
+ public class MemoryTrackerInterface extends Binder {
+ MemoryTracker getService() {
+ return MemoryTracker.this;
+ }
+ }
+
+ private final IBinder mBinder = new MemoryTrackerInterface();
+
+ public IBinder onBind(Intent intent) {
+ mHandler.sendEmptyMessage(MSG_START);
+
+ return mBinder;
+ }
+}
diff --git a/src/com/android/launcher3/WeightWatcher.java b/src/com/android/launcher3/WeightWatcher.java
index 15de93cb7..91d79a814 100644
--- a/src/com/android/launcher3/WeightWatcher.java
+++ b/src/com/android/launcher3/WeightWatcher.java
@@ -16,33 +16,36 @@
package com.android.launcher3;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
-import android.os.Debug;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
public class WeightWatcher extends LinearLayout {
- private static final long UPDATE_RATE = 5000;
+ private static final int RAM_GRAPH_RSS_COLOR = 0xFF990000;
+ private static final int RAM_GRAPH_PSS_COLOR = 0xFF99CC00;
+ private static final int TEXT_COLOR = 0xFFFFFFFF;
+ private static final int BACKGROUND_COLOR = 0xa0000000;
- private static final int RAM_GRAPH_COLOR = 0x9099CC00;
- private static final int TEXT_COLOR = 0x90FFFFFF;
- private static final int BACKGROUND_COLOR = 0x40000000;
+ private static final int UPDATE_RATE = 5000;
private static final int MSG_START = 1;
private static final int MSG_STOP = 2;
private static final int MSG_UPDATE = 3;
- TextView mRamText;
- GraphView mRamGraph;
- TextView mUptimeText;
-
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message m) {
@@ -54,46 +57,45 @@ public class WeightWatcher extends LinearLayout {
mHandler.removeMessages(MSG_UPDATE);
break;
case MSG_UPDATE:
- update();
+ final int N = getChildCount();
+ for (int i=0; i<N; i++) {
+ ((ProcessWatcher) getChildAt(i)).update();
+ }
mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE);
break;
}
}
};
+ private MemoryTracker mMemoryService;
public WeightWatcher(Context context, AttributeSet attrs) {
super(context, attrs);
- final float dp = getResources().getDisplayMetrics().density;
-
- setBackgroundColor(BACKGROUND_COLOR);
-
- mRamText = new TextView(getContext());
- mUptimeText = new TextView(getContext());
- mRamText.setTextColor(TEXT_COLOR);
- mUptimeText.setTextColor(TEXT_COLOR);
-
- final int p = (int)(4*dp);
- setPadding(p, 0, p, 0);
+ ServiceConnection connection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mMemoryService = ((MemoryTracker.MemoryTrackerInterface)service).getService();
+ initViews();
+ }
- mRamGraph = new GraphView(getContext());
+ public void onServiceDisconnected(ComponentName className) {
+ mMemoryService = null;
+ }
+ };
+ context.bindService(new Intent(context, MemoryTracker.class),
+ connection, Context.BIND_AUTO_CREATE);
- LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT
- );
- wrapParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
- wrapParams.setMarginEnd((int)(8*dp));
+ setOrientation(LinearLayout.VERTICAL);
- LinearLayout.LayoutParams fillParams = new LinearLayout.LayoutParams(
- 0,
- LinearLayout.LayoutParams.MATCH_PARENT,
- 1.0f
- );
+ setBackgroundColor(BACKGROUND_COLOR);
+ }
- addView(mUptimeText, wrapParams);
- addView(mRamText, wrapParams);
- addView(mRamGraph, fillParams);
+ public void initViews() {
+ int[] processes = mMemoryService.getTrackedProcesses();
+ for (int i=0; i<processes.length; i++) {
+ final ProcessWatcher v = new ProcessWatcher(getContext());
+ v.setPid(processes[i]);
+ addView(v);
+ }
}
public WeightWatcher(Context context) {
@@ -107,12 +109,6 @@ public class WeightWatcher extends LinearLayout {
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mRamText.setTextSize(h * 0.25f);
- mUptimeText.setTextSize(h * 0.25f);
- }
-
- @Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mHandler.sendEmptyMessage(MSG_STOP);
@@ -147,51 +143,98 @@ public class WeightWatcher extends LinearLayout {
return sb.toString();
}
- void update() {
- final long pss = Debug.getPss();
+ public class ProcessWatcher extends LinearLayout {
+ GraphView mRamGraph;
+ TextView mText;
+ int mPid;
+ private MemoryTracker.ProcessMemInfo mMemInfo;
- mRamGraph.add(pss);
- mRamText.setText("pss=" + pss);
- mUptimeText.setText("uptime=" + getUptimeString());
+ public ProcessWatcher(Context context) {
+ this(context, null);
+ }
- postInvalidate();
- }
+ public ProcessWatcher(Context context, AttributeSet attrs) {
+ super(context, attrs);
- public static class GraphView extends View {
- final long[] data = new long[256];
- long max = 1;
- int head = 0;
+ final float dp = getResources().getDisplayMetrics().density;
- Paint paint;
+ mText = new TextView(getContext());
+ mText.setTextColor(TEXT_COLOR);
+ mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, 10 * dp);
+ mText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
- public GraphView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ final int p = (int)(2*dp);
+ setPadding(p, 0, p, 0);
+
+ mRamGraph = new GraphView(getContext());
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ 0,
+ (int)(22 * dp),
+ 1f
+ );
- paint = new Paint();
- paint.setColor(RAM_GRAPH_COLOR);
+ addView(mText, params);
+ params.leftMargin = (int)(4*dp);
+ params.weight = 0f;
+ params.width = (int)(200 * dp);
+ addView(mRamGraph, params);
}
- public GraphView(Context context) {
- this(context, null);
+ public void setPid(int pid) {
+ mPid = pid;
+ mMemInfo = mMemoryService.getMemInfo(mPid);
}
- public void add(long dat) {
- head = (head+1) % data.length;
- data[head] = dat;
- if (dat > max) max = dat;
- invalidate();
+ public void update() {
+ //Log.v("WeightWatcher.ProcessWatcher",
+ // "MSG_UPDATE pss=" + mMemInfo.currentPss);
+ mText.setText("(" + mMemInfo.name + "/" + mPid + ") up " + getUptimeString()
+ + " P=" + mMemInfo.currentPss
+ + " U=" + mMemInfo.currentUss
+ );
+ mRamGraph.invalidate();
}
- @Override
- public void onDraw(Canvas c) {
- int w = c.getWidth();
- int h = c.getHeight();
+ public class GraphView extends View {
+ Paint pssPaint, ussPaint, headPaint;
+
+ public GraphView(Context context, AttributeSet attrs) {
+ super(context, attrs);
- final float barWidth = (float) w / data.length;
- final float scale = (float) h / max;
+ pssPaint = new Paint();
+ pssPaint.setColor(RAM_GRAPH_PSS_COLOR);
+ ussPaint = new Paint();
+ ussPaint.setColor(RAM_GRAPH_RSS_COLOR);
+ headPaint = new Paint();
+ headPaint.setColor(Color.WHITE);
+ }
+
+ public GraphView(Context context) {
+ this(context, null);
+ }
- for (int i=0; i<data.length; i++) {
- c.drawRect(i * barWidth, h - scale * data[i], (i+1) * barWidth, h, paint);
+ @Override
+ public void onDraw(Canvas c) {
+ int w = c.getWidth();
+ int h = c.getHeight();
+
+ if (mMemInfo == null) return;
+
+ final int N = mMemInfo.pss.length;
+ final float barStep = (float) w / N;
+ final float barWidth = Math.max(1, barStep);
+ final float scale = (float) h / mMemInfo.max;
+
+ int i;
+ float x;
+ for (i=0; i<N; i++) {
+ x = i * barStep;
+ c.drawRect(x, h - scale * mMemInfo.pss[i], x + barWidth, h, pssPaint);
+ c.drawRect(x, h - scale * mMemInfo.uss[i], x + barWidth, h, ussPaint);
+ }
+ x = mMemInfo.head * barStep;
+ c.drawRect(x, 0, x + barWidth, h, headPaint);
}
}
}