Commit b9eb2865 authored by Daniel Sandler's avatar Daniel Sandler
Browse files

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
parent 211667e4
......@@ -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"
......
......@@ -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)
);
}
......
......@@ -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;
......
/*
* 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;
......
/*
* 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;
}
}
......@@ -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) {
......@@ -106,12 +108,6 @@ public class WeightWatcher extends LinearLayout {
mHandler.sendEmptyMessage(MSG_START);
}
@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();
......@@ -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);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment