1 package com.google.android.experimental.svcmonitor; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.IBinder; 6 import android.os.SystemClock; 7 import android.util.Log; 8 9 import java.io.IOException; 10 import java.io.InputStreamReader; 11 import java.io.BufferedReader; 12 import java.io.FileInputStream; 13 import java.lang.Runnable; 14 import java.lang.Thread; 15 import java.util.Set; 16 17 public class SvcMonitor extends Service { 18 public static final String TAG = "svcmonitor"; 19 String javaProc, halProc; 20 volatile Thread tMonitor; 21 int period; 22 SvcMonitor()23 public SvcMonitor() {}; 24 25 @Override onStartCommand(Intent intent, int flags, int startId)26 public int onStartCommand(Intent intent, int flags, int startId) { 27 if (intent == null) { 28 stopSelf(); 29 return 0; 30 } 31 Log.d(TAG, "Starting SvcMonitor"); 32 if ("stop".equals(intent.getAction())) { 33 stopService(); 34 } else if ("start".equals(intent.getAction())) { 35 startMonitor(intent); 36 } else if ("change".equals(intent.getAction())) { 37 changeConfig(intent); 38 } else { 39 Log.d(TAG, "unknown action: + " + intent.getAction()); 40 } 41 return 0; 42 } 43 changeConfig(Intent intent)44 private void changeConfig(Intent intent) { 45 if (tMonitor == null) { 46 Log.d(TAG, "Service not active. Start service first"); 47 return; 48 } 49 stopThread(); 50 startMonitor(intent); 51 } 52 startMonitor(Intent intent)53 private void startMonitor(Intent intent) { 54 if (tMonitor != null) { 55 Log.d(TAG, "thread already active"); 56 return; 57 } 58 javaProc = intent.getStringExtra("java"); 59 halProc = intent.getStringExtra("hal"); 60 period = intent.getIntExtra("period", 1000); 61 if (javaProc == null || halProc == null || period < 100) { 62 Log.d(TAG, "Failed starting monitor, invalid arguments."); 63 stopSelf(); 64 return; 65 } 66 Runnable monitor = new MonitorRunnable(this); 67 tMonitor = new Thread(monitor); 68 tMonitor.start(); 69 } 70 stopService()71 private void stopService() { 72 stopThread(); 73 stopSelf(); 74 Log.d(TAG, "SvcMonitor stopped"); 75 } 76 stopThread()77 private void stopThread() { 78 if (tMonitor == null) { 79 Log.d(TAG, "no active thread"); 80 return; 81 } 82 Log.d(TAG, "interrupting monitor thread"); 83 tMonitor.interrupt(); 84 try { 85 tMonitor.join(); 86 } catch (InterruptedException e) { 87 Log.d(TAG, "Unable to finish monitor thread"); 88 } 89 tMonitor = null; 90 } 91 92 @Override onDestroy()93 public void onDestroy() { 94 super.onDestroy(); 95 } 96 97 @Override onBind(Intent intent)98 public IBinder onBind(Intent intent) { 99 throw new UnsupportedOperationException("Not yet implemented"); 100 } 101 102 public static class MonitorRunnable implements Runnable { 103 long java_time_old, hal_time_old, cpu_time_old = -1; 104 String javaPID, halPID; 105 SvcMonitor svcmonitor; 106 static String javaProcTAG; 107 int period; 108 MonitorRunnable(SvcMonitor svcmonitor)109 public MonitorRunnable(SvcMonitor svcmonitor) { 110 this.svcmonitor = svcmonitor; 111 this.period = svcmonitor.period; 112 javaPID = getPIDof(svcmonitor.javaProc); 113 halPID = getPIDof(svcmonitor.halProc); 114 java_time_old = getPsTime(javaPID); 115 hal_time_old = getPsTime(halPID); 116 cpu_time_old = getPsTime(""); 117 javaProcTAG = String.valueOf(svcmonitor.javaProc.toCharArray()); 118 } 119 120 @Override run()121 public void run() { 122 if (halPID.isEmpty() || javaPID.isEmpty()) { 123 Log.d(javaProcTAG, "No such process: " + 124 (halPID.isEmpty() ? svcmonitor.halProc : svcmonitor.javaProc)); 125 return; 126 } 127 while (!Thread.interrupted()) { 128 calculateUsage(); 129 SystemClock.sleep(period); 130 } 131 Log.d(TAG, "Stopping monitor thread"); 132 } 133 calculateUsage()134 private void calculateUsage() { 135 long java_time = getPsTime(javaPID); 136 long hal_time = getPsTime(halPID); 137 long cpu_time = getPsTime(""); 138 139 if (cpu_time_old >= 0) { 140 float java_diff = (float) (java_time - java_time_old); 141 float hal_diff = (float) (hal_time - hal_time_old); 142 float cpu_diff = (float) (cpu_time - cpu_time_old); 143 Log.w(javaProcTAG, "\n----------------\n"); 144 Log.w(javaProcTAG, "JAVA level CPU: " 145 + (java_diff * 100.0 / cpu_diff) + "%\n"); 146 Log.w(javaProcTAG, " HAL level CPU: " 147 + (hal_diff * 100.0 / cpu_diff) + "%\n"); 148 Log.w(javaProcTAG, " SYS level CPU: " 149 + ((java_diff + hal_diff) * 100.0 / cpu_diff) + "%\n"); 150 } else { 151 Log.w(TAG, "Waiting for status\n"); 152 } 153 154 java_time_old = java_time; 155 hal_time_old = hal_time; 156 cpu_time_old = cpu_time; 157 } 158 getPIDof(String psName)159 private String getPIDof(String psName) { 160 String pid = ""; 161 162 try { 163 String[] cmd = {"/system/bin/sh", "-c", "ps | grep " + psName}; 164 Process ps = Runtime.getRuntime().exec(cmd); 165 BufferedReader in = new BufferedReader( 166 new InputStreamReader(ps.getInputStream())); 167 String temp = in.readLine(); 168 if (temp == null || temp.isEmpty()) 169 throw new IOException("No such process: " + psName); 170 pid = temp.split(" +")[1]; 171 in.close(); 172 } catch (IOException e) { 173 Log.d(javaProcTAG, "Error finding PID of process: " + psName + "\n", e); 174 } 175 return pid; 176 } 177 getPsTime(String pid)178 private long getPsTime(String pid) { 179 String psStat = getPsStat("/" + pid); 180 String[] statBreakDown = psStat.split(" +"); 181 long psTime; 182 183 if (pid.isEmpty()) { 184 psTime = Long.parseLong(statBreakDown[1]) 185 + Long.parseLong(statBreakDown[2]) 186 + Long.parseLong(statBreakDown[3]) 187 + Long.parseLong(statBreakDown[4]); 188 } else { 189 psTime = Long.parseLong(statBreakDown[13]) 190 + Long.parseLong(statBreakDown[14]); 191 } 192 193 return psTime; 194 } 195 getPsStat(String psname)196 private String getPsStat(String psname) { 197 String stat = ""; 198 try { 199 FileInputStream fs = new FileInputStream("/proc" + psname + "/stat"); 200 BufferedReader br = new BufferedReader(new InputStreamReader(fs)); 201 stat = br.readLine(); 202 fs.close(); 203 } catch (IOException e) { 204 Log.d(TAG, "Error retreiving stat. \n"); 205 } 206 return stat; 207 } 208 } 209 } 210