blob: e05b57061155fd502830d3b6b773bcbbcd977d12 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.Service;
20import android.content.Context;
21import android.content.Intent;
22import android.graphics.Canvas;
23import android.graphics.Paint;
24import android.graphics.PixelFormat;
25import android.os.Handler;
26import android.os.IBinder;
27import android.os.Message;
28import android.view.Gravity;
29import android.view.View;
30import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
32public class LoadAverageService extends Service {
33 private View mView;
34
35 private static final class Stats extends ProcessStats {
36 String mLoadText;
37 int mLoadWidth;
38
39 private final Paint mPaint;
40
41 Stats(Paint paint) {
42 super(false);
43 mPaint = paint;
44 }
45
46 @Override
47 public void onLoadChanged(float load1, float load5, float load15) {
48 mLoadText = load1 + " / " + load5 + " / " + load15;
49 mLoadWidth = (int)mPaint.measureText(mLoadText);
50 }
51
52 @Override
53 public int onMeasureProcessName(String name) {
54 return (int)mPaint.measureText(name);
55 }
56 }
57
58 private class LoadView extends View {
59 private Handler mHandler = new Handler() {
60 @Override
61 public void handleMessage(Message msg) {
62 if (msg.what == 1) {
63 mStats.update();
64 updateDisplay();
65 Message m = obtainMessage(1);
66 sendMessageDelayed(m, 2000);
67 }
68 }
69 };
70
71 private final Stats mStats;
72
73 private Paint mLoadPaint;
74 private Paint mAddedPaint;
75 private Paint mRemovedPaint;
76 private Paint mShadowPaint;
77 private Paint mShadow2Paint;
78 private Paint mIrqPaint;
79 private Paint mSystemPaint;
80 private Paint mUserPaint;
81 private float mAscent;
82 private int mFH;
83
84 private int mNeededWidth;
85 private int mNeededHeight;
86
87 LoadView(Context c) {
88 super(c);
89
90 setPadding(4, 4, 4, 4);
91 //setBackgroundResource(com.android.internal.R.drawable.load_average_background);
92
Dianne Hackbornce86ba82011-07-13 19:33:41 -070093 // Need to scale text size by density... but we won't do it
94 // linearly, because with higher dps it is nice to squeeze the
95 // text a bit to fit more of it. And with lower dps, trying to
96 // go much smaller will result in unreadable text.
97 int textSize = 10;
98 float density = c.getResources().getDisplayMetrics().density;
99 if (density < 1) {
100 textSize = 9;
101 } else {
102 textSize = (int)(10*density);
103 if (textSize < 10) {
104 textSize = 10;
105 }
106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 mLoadPaint = new Paint();
108 mLoadPaint.setAntiAlias(true);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700109 mLoadPaint.setTextSize(textSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 mLoadPaint.setARGB(255, 255, 255, 255);
111
112 mAddedPaint = new Paint();
113 mAddedPaint.setAntiAlias(true);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700114 mAddedPaint.setTextSize(textSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 mAddedPaint.setARGB(255, 128, 255, 128);
116
117 mRemovedPaint = new Paint();
118 mRemovedPaint.setAntiAlias(true);
119 mRemovedPaint.setStrikeThruText(true);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700120 mRemovedPaint.setTextSize(textSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 mRemovedPaint.setARGB(255, 255, 128, 128);
122
123 mShadowPaint = new Paint();
124 mShadowPaint.setAntiAlias(true);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700125 mShadowPaint.setTextSize(textSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 //mShadowPaint.setFakeBoldText(true);
127 mShadowPaint.setARGB(192, 0, 0, 0);
128 mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
129
130 mShadow2Paint = new Paint();
131 mShadow2Paint.setAntiAlias(true);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700132 mShadow2Paint.setTextSize(textSize);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 //mShadow2Paint.setFakeBoldText(true);
134 mShadow2Paint.setARGB(192, 0, 0, 0);
135 mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
136
137 mIrqPaint = new Paint();
138 mIrqPaint.setARGB(0x80, 0, 0, 0xff);
139 mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000);
140 mSystemPaint = new Paint();
141 mSystemPaint.setARGB(0x80, 0xff, 0, 0);
142 mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
143 mUserPaint = new Paint();
144 mUserPaint.setARGB(0x80, 0, 0xff, 0);
145 mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
146
147 mAscent = mLoadPaint.ascent();
148 float descent = mLoadPaint.descent();
149 mFH = (int)(descent - mAscent + .5f);
150
151 mStats = new Stats(mLoadPaint);
152 mStats.init();
153 updateDisplay();
154 }
155
156 @Override
157 protected void onAttachedToWindow() {
158 super.onAttachedToWindow();
159 mHandler.sendEmptyMessage(1);
160 }
161
162 @Override
163 protected void onDetachedFromWindow() {
164 super.onDetachedFromWindow();
165 mHandler.removeMessages(1);
166 }
167
168 @Override
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700169 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
170 setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
171 resolveSize(mNeededHeight, heightMeasureSpec));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 }
173
174 @Override
175 public void onDraw(Canvas canvas) {
176 super.onDraw(canvas);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700177 final int W = mNeededWidth;
178 final int RIGHT = getWidth()-1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
180 final Stats stats = mStats;
181 final int userTime = stats.getLastUserTime();
182 final int systemTime = stats.getLastSystemTime();
183 final int iowaitTime = stats.getLastIoWaitTime();
184 final int irqTime = stats.getLastIrqTime();
185 final int softIrqTime = stats.getLastSoftIrqTime();
186 final int idleTime = stats.getLastIdleTime();
187
188 final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime;
189 if (totalTime == 0) {
190 return;
191 }
192 int userW = (userTime*W)/totalTime;
193 int systemW = (systemTime*W)/totalTime;
194 int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
195
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700196 int x = RIGHT - mPaddingRight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 int top = mPaddingTop + 2;
198 int bottom = mPaddingTop + mFH - 2;
199
200 if (irqW > 0) {
201 canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint);
202 x -= irqW;
203 }
204 if (systemW > 0) {
205 canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
206 x -= systemW;
207 }
208 if (userW > 0) {
209 canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
210 x -= userW;
211 }
212
213 int y = mPaddingTop - (int)mAscent;
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700214 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 y-1, mShadowPaint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700216 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 y+1, mShadowPaint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700218 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 y-1, mShadow2Paint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700220 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 y+1, mShadow2Paint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700222 canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 y, mLoadPaint);
224
225 int N = stats.countWorkingStats();
226 for (int i=0; i<N; i++) {
227 Stats.Stats st = stats.getWorkingStats(i);
228 y += mFH;
229 top += mFH;
230 bottom += mFH;
231
232 userW = (st.rel_utime*W)/totalTime;
233 systemW = (st.rel_stime*W)/totalTime;
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700234 x = RIGHT - mPaddingRight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 if (systemW > 0) {
236 canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
237 x -= systemW;
238 }
239 if (userW > 0) {
240 canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
241 x -= userW;
242 }
243
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700244 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 y-1, mShadowPaint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700246 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 y+1, mShadowPaint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700248 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 y-1, mShadow2Paint);
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700250 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 y+1, mShadow2Paint);
252 Paint p = mLoadPaint;
253 if (st.added) p = mAddedPaint;
254 if (st.removed) p = mRemovedPaint;
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700255 canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 }
257 }
258
259 void updateDisplay() {
260 final Stats stats = mStats;
261 final int NW = stats.countWorkingStats();
262
263 int maxWidth = stats.mLoadWidth;
264 for (int i=0; i<NW; i++) {
265 Stats.Stats st = stats.getWorkingStats(i);
266 if (st.nameWidth > maxWidth) {
267 maxWidth = st.nameWidth;
268 }
269 }
270
271 int neededWidth = mPaddingLeft + mPaddingRight + maxWidth;
272 int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW));
273 if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
274 mNeededWidth = neededWidth;
275 mNeededHeight = neededHeight;
276 requestLayout();
277 } else {
278 invalidate();
279 }
280 }
281 }
282
283 @Override
284 public void onCreate() {
285 super.onCreate();
286 mView = new LoadView(this);
287 WindowManager.LayoutParams params = new WindowManager.LayoutParams(
Dianne Hackbornce86ba82011-07-13 19:33:41 -0700288 WindowManager.LayoutParams.MATCH_PARENT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 WindowManager.LayoutParams.WRAP_CONTENT,
Jeff Brown3b2b3542010-10-15 00:54:27 -0700290 WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
292 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
293 PixelFormat.TRANSLUCENT);
294 params.gravity = Gravity.RIGHT | Gravity.TOP;
295 params.setTitle("Load Average");
Dianne Hackborn2ed99462011-07-01 19:02:52 -0700296 WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 wm.addView(mView, params);
298 }
299
300 @Override
301 public void onDestroy() {
302 super.onDestroy();
Dianne Hackborn2ed99462011-07-01 19:02:52 -0700303 ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 mView = null;
305 }
306
307 @Override
308 public IBinder onBind(Intent intent) {
309 return null;
310 }
311
312}