Files
frameworks_base/services/java/com/android/server/LoadAverageService.java
Dianne Hackborn ce86ba86df Improve handling of low memory.
Now classify background processes into a set of bins of how much
memory they should try to clear.  The last bin also involves
destroying all activities in that process.

Removed the old code for the simulator that is no longer needed
(yay).  The debugging features it had are now integrated into the
regular oom adj code.

Small fixes to load average service.

Change-Id: Ic8df401714b188c73b50dbc8f8e6345b58f1f3a0
2011-07-14 10:39:39 -07:00

313 lines
11 KiB
Java

/*
* Copyright (C) 2007 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;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
public class LoadAverageService extends Service {
private View mView;
private static final class Stats extends ProcessStats {
String mLoadText;
int mLoadWidth;
private final Paint mPaint;
Stats(Paint paint) {
super(false);
mPaint = paint;
}
@Override
public void onLoadChanged(float load1, float load5, float load15) {
mLoadText = load1 + " / " + load5 + " / " + load15;
mLoadWidth = (int)mPaint.measureText(mLoadText);
}
@Override
public int onMeasureProcessName(String name) {
return (int)mPaint.measureText(name);
}
}
private class LoadView extends View {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
mStats.update();
updateDisplay();
Message m = obtainMessage(1);
sendMessageDelayed(m, 2000);
}
}
};
private final Stats mStats;
private Paint mLoadPaint;
private Paint mAddedPaint;
private Paint mRemovedPaint;
private Paint mShadowPaint;
private Paint mShadow2Paint;
private Paint mIrqPaint;
private Paint mSystemPaint;
private Paint mUserPaint;
private float mAscent;
private int mFH;
private int mNeededWidth;
private int mNeededHeight;
LoadView(Context c) {
super(c);
setPadding(4, 4, 4, 4);
//setBackgroundResource(com.android.internal.R.drawable.load_average_background);
// Need to scale text size by density... but we won't do it
// linearly, because with higher dps it is nice to squeeze the
// text a bit to fit more of it. And with lower dps, trying to
// go much smaller will result in unreadable text.
int textSize = 10;
float density = c.getResources().getDisplayMetrics().density;
if (density < 1) {
textSize = 9;
} else {
textSize = (int)(10*density);
if (textSize < 10) {
textSize = 10;
}
}
mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
mLoadPaint.setTextSize(textSize);
mLoadPaint.setARGB(255, 255, 255, 255);
mAddedPaint = new Paint();
mAddedPaint.setAntiAlias(true);
mAddedPaint.setTextSize(textSize);
mAddedPaint.setARGB(255, 128, 255, 128);
mRemovedPaint = new Paint();
mRemovedPaint.setAntiAlias(true);
mRemovedPaint.setStrikeThruText(true);
mRemovedPaint.setTextSize(textSize);
mRemovedPaint.setARGB(255, 255, 128, 128);
mShadowPaint = new Paint();
mShadowPaint.setAntiAlias(true);
mShadowPaint.setTextSize(textSize);
//mShadowPaint.setFakeBoldText(true);
mShadowPaint.setARGB(192, 0, 0, 0);
mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
mShadow2Paint = new Paint();
mShadow2Paint.setAntiAlias(true);
mShadow2Paint.setTextSize(textSize);
//mShadow2Paint.setFakeBoldText(true);
mShadow2Paint.setARGB(192, 0, 0, 0);
mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
mIrqPaint = new Paint();
mIrqPaint.setARGB(0x80, 0, 0, 0xff);
mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000);
mSystemPaint = new Paint();
mSystemPaint.setARGB(0x80, 0xff, 0, 0);
mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
mUserPaint = new Paint();
mUserPaint.setARGB(0x80, 0, 0xff, 0);
mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
mAscent = mLoadPaint.ascent();
float descent = mLoadPaint.descent();
mFH = (int)(descent - mAscent + .5f);
mStats = new Stats(mLoadPaint);
mStats.init();
updateDisplay();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mHandler.sendEmptyMessage(1);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mHandler.removeMessages(1);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
resolveSize(mNeededHeight, heightMeasureSpec));
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int W = mNeededWidth;
final int RIGHT = getWidth()-1;
final Stats stats = mStats;
final int userTime = stats.getLastUserTime();
final int systemTime = stats.getLastSystemTime();
final int iowaitTime = stats.getLastIoWaitTime();
final int irqTime = stats.getLastIrqTime();
final int softIrqTime = stats.getLastSoftIrqTime();
final int idleTime = stats.getLastIdleTime();
final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime;
if (totalTime == 0) {
return;
}
int userW = (userTime*W)/totalTime;
int systemW = (systemTime*W)/totalTime;
int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
int x = RIGHT - mPaddingRight;
int top = mPaddingTop + 2;
int bottom = mPaddingTop + mFH - 2;
if (irqW > 0) {
canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint);
x -= irqW;
}
if (systemW > 0) {
canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
x -= systemW;
}
if (userW > 0) {
canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
x -= userW;
}
int y = mPaddingTop - (int)mAscent;
canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
y-1, mShadowPaint);
canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
y+1, mShadowPaint);
canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
y-1, mShadow2Paint);
canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
y+1, mShadow2Paint);
canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth,
y, mLoadPaint);
int N = stats.countWorkingStats();
for (int i=0; i<N; i++) {
Stats.Stats st = stats.getWorkingStats(i);
y += mFH;
top += mFH;
bottom += mFH;
userW = (st.rel_utime*W)/totalTime;
systemW = (st.rel_stime*W)/totalTime;
x = RIGHT - mPaddingRight;
if (systemW > 0) {
canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
x -= systemW;
}
if (userW > 0) {
canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
x -= userW;
}
canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
y-1, mShadowPaint);
canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
y+1, mShadowPaint);
canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
y-1, mShadow2Paint);
canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
y+1, mShadow2Paint);
Paint p = mLoadPaint;
if (st.added) p = mAddedPaint;
if (st.removed) p = mRemovedPaint;
canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p);
}
}
void updateDisplay() {
final Stats stats = mStats;
final int NW = stats.countWorkingStats();
int maxWidth = stats.mLoadWidth;
for (int i=0; i<NW; i++) {
Stats.Stats st = stats.getWorkingStats(i);
if (st.nameWidth > maxWidth) {
maxWidth = st.nameWidth;
}
}
int neededWidth = mPaddingLeft + mPaddingRight + maxWidth;
int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW));
if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
mNeededWidth = neededWidth;
mNeededHeight = neededHeight;
requestLayout();
} else {
invalidate();
}
}
}
@Override
public void onCreate() {
super.onCreate();
mView = new LoadView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}
@Override
public void onDestroy() {
super.onDestroy();
((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
mView = null;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}