1 /* 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 17 package com.android.server; 18 19 import android.app.Service; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.graphics.Canvas; 23 import android.graphics.Paint; 24 import android.graphics.PixelFormat; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.os.Message; 28 import android.view.Gravity; 29 import android.view.View; 30 import android.view.WindowManager; 31 import android.view.WindowManagerImpl; 32 33 public class LoadAverageService extends Service { 34 private View mView; 35 36 private static final class Stats extends ProcessStats { 37 String mLoadText; 38 int mLoadWidth; 39 40 private final Paint mPaint; 41 42 Stats(Paint paint) { 43 super(false); 44 mPaint = paint; 45 } 46 47 @Override 48 public void onLoadChanged(float load1, float load5, float load15) { 49 mLoadText = load1 + " / " + load5 + " / " + load15; 50 mLoadWidth = (int)mPaint.measureText(mLoadText); 51 } 52 53 @Override 54 public int onMeasureProcessName(String name) { 55 return (int)mPaint.measureText(name); 56 } 57 } 58 59 private class LoadView extends View { 60 private Handler mHandler = new Handler() { 61 @Override 62 public void handleMessage(Message msg) { 63 if (msg.what == 1) { 64 mStats.update(); 65 updateDisplay(); 66 Message m = obtainMessage(1); 67 sendMessageDelayed(m, 2000); 68 } 69 } 70 }; 71 72 private final Stats mStats; 73 74 private Paint mLoadPaint; 75 private Paint mAddedPaint; 76 private Paint mRemovedPaint; 77 private Paint mShadowPaint; 78 private Paint mShadow2Paint; 79 private Paint mIrqPaint; 80 private Paint mSystemPaint; 81 private Paint mUserPaint; 82 private float mAscent; 83 private int mFH; 84 85 private int mNeededWidth; 86 private int mNeededHeight; 87 88 LoadView(Context c) { 89 super(c); 90 91 setPadding(4, 4, 4, 4); 92 //setBackgroundResource(com.android.internal.R.drawable.load_average_background); 93 94 mLoadPaint = new Paint(); 95 mLoadPaint.setAntiAlias(true); 96 mLoadPaint.setTextSize(10); 97 mLoadPaint.setARGB(255, 255, 255, 255); 98 99 mAddedPaint = new Paint(); 100 mAddedPaint.setAntiAlias(true); 101 mAddedPaint.setTextSize(10); 102 mAddedPaint.setARGB(255, 128, 255, 128); 103 104 mRemovedPaint = new Paint(); 105 mRemovedPaint.setAntiAlias(true); 106 mRemovedPaint.setStrikeThruText(true); 107 mRemovedPaint.setTextSize(10); 108 mRemovedPaint.setARGB(255, 255, 128, 128); 109 110 mShadowPaint = new Paint(); 111 mShadowPaint.setAntiAlias(true); 112 mShadowPaint.setTextSize(10); 113 //mShadowPaint.setFakeBoldText(true); 114 mShadowPaint.setARGB(192, 0, 0, 0); 115 mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000); 116 117 mShadow2Paint = new Paint(); 118 mShadow2Paint.setAntiAlias(true); 119 mShadow2Paint.setTextSize(10); 120 //mShadow2Paint.setFakeBoldText(true); 121 mShadow2Paint.setARGB(192, 0, 0, 0); 122 mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000); 123 124 mIrqPaint = new Paint(); 125 mIrqPaint.setARGB(0x80, 0, 0, 0xff); 126 mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000); 127 mSystemPaint = new Paint(); 128 mSystemPaint.setARGB(0x80, 0xff, 0, 0); 129 mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); 130 mUserPaint = new Paint(); 131 mUserPaint.setARGB(0x80, 0, 0xff, 0); 132 mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000); 133 134 mAscent = mLoadPaint.ascent(); 135 float descent = mLoadPaint.descent(); 136 mFH = (int)(descent - mAscent + .5f); 137 138 mStats = new Stats(mLoadPaint); 139 mStats.init(); 140 updateDisplay(); 141 } 142 143 @Override 144 protected void onAttachedToWindow() { 145 super.onAttachedToWindow(); 146 mHandler.sendEmptyMessage(1); 147 } 148 149 @Override 150 protected void onDetachedFromWindow() { 151 super.onDetachedFromWindow(); 152 mHandler.removeMessages(1); 153 } 154 155 @Override 156 protected void onMeasure(int widthMeasureSpect, int heightMeasureSpec) { 157 setMeasuredDimension(mNeededWidth, mNeededHeight); 158 } 159 160 @Override 161 public void onDraw(Canvas canvas) { 162 super.onDraw(canvas); 163 final int W = getWidth(); 164 165 final Stats stats = mStats; 166 final int userTime = stats.getLastUserTime(); 167 final int systemTime = stats.getLastSystemTime(); 168 final int iowaitTime = stats.getLastIoWaitTime(); 169 final int irqTime = stats.getLastIrqTime(); 170 final int softIrqTime = stats.getLastSoftIrqTime(); 171 final int idleTime = stats.getLastIdleTime(); 172 173 final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime; 174 if (totalTime == 0) { 175 return; 176 } 177 int userW = (userTime*W)/totalTime; 178 int systemW = (systemTime*W)/totalTime; 179 int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime; 180 181 int x = W - mPaddingRight; 182 int top = mPaddingTop + 2; 183 int bottom = mPaddingTop + mFH - 2; 184 185 if (irqW > 0) { 186 canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint); 187 x -= irqW; 188 } 189 if (systemW > 0) { 190 canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); 191 x -= systemW; 192 } 193 if (userW > 0) { 194 canvas.drawRect(x-userW, top, x, bottom, mUserPaint); 195 x -= userW; 196 } 197 198 int y = mPaddingTop - (int)mAscent; 199 canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1, 200 y-1, mShadowPaint); 201 canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1, 202 y+1, mShadowPaint); 203 canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1, 204 y-1, mShadow2Paint); 205 canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1, 206 y+1, mShadow2Paint); 207 canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth, 208 y, mLoadPaint); 209 210 int N = stats.countWorkingStats(); 211 for (int i=0; i<N; i++) { 212 Stats.Stats st = stats.getWorkingStats(i); 213 y += mFH; 214 top += mFH; 215 bottom += mFH; 216 217 userW = (st.rel_utime*W)/totalTime; 218 systemW = (st.rel_stime*W)/totalTime; 219 x = W - mPaddingRight; 220 if (systemW > 0) { 221 canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint); 222 x -= systemW; 223 } 224 if (userW > 0) { 225 canvas.drawRect(x-userW, top, x, bottom, mUserPaint); 226 x -= userW; 227 } 228 229 canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1, 230 y-1, mShadowPaint); 231 canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1, 232 y+1, mShadowPaint); 233 canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1, 234 y-1, mShadow2Paint); 235 canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1, 236 y+1, mShadow2Paint); 237 Paint p = mLoadPaint; 238 if (st.added) p = mAddedPaint; 239 if (st.removed) p = mRemovedPaint; 240 canvas.drawText(st.name, W-mPaddingRight-st.nameWidth, y, p); 241 } 242 } 243 244 void updateDisplay() { 245 final Stats stats = mStats; 246 final int NW = stats.countWorkingStats(); 247 248 int maxWidth = stats.mLoadWidth; 249 for (int i=0; i<NW; i++) { 250 Stats.Stats st = stats.getWorkingStats(i); 251 if (st.nameWidth > maxWidth) { 252 maxWidth = st.nameWidth; 253 } 254 } 255 256 int neededWidth = mPaddingLeft + mPaddingRight + maxWidth; 257 int neededHeight = mPaddingTop + mPaddingBottom + (mFH*(1+NW)); 258 if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) { 259 mNeededWidth = neededWidth; 260 mNeededHeight = neededHeight; 261 requestLayout(); 262 } else { 263 invalidate(); 264 } 265 } 266 } 267 268 @Override 269 public void onCreate() { 270 super.onCreate(); 271 mView = new LoadView(this); 272 WindowManager.LayoutParams params = new WindowManager.LayoutParams( 273 WindowManager.LayoutParams.WRAP_CONTENT, 274 WindowManager.LayoutParams.WRAP_CONTENT, 275 WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY, 276 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 277 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, 278 PixelFormat.TRANSLUCENT); 279 params.gravity = Gravity.RIGHT | Gravity.TOP; 280 params.setTitle("Load Average"); 281 WindowManagerImpl wm = (WindowManagerImpl)getSystemService(WINDOW_SERVICE); 282 wm.addView(mView, params); 283 } 284 285 @Override 286 public void onDestroy() { 287 super.onDestroy(); 288 ((WindowManagerImpl)getSystemService(WINDOW_SERVICE)).removeView(mView); 289 mView = null; 290 } 291 292 @Override 293 public IBinder onBind(Intent intent) { 294 return null; 295 } 296 297 } 298