package com.google.android.experimental.svcmonitor; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.SystemClock; import android.util.Log; import java.io.IOException; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.FileInputStream; import java.lang.Runnable; import java.lang.Thread; import java.util.Set; public class SvcMonitor extends Service { public static final String TAG = "svcmonitor"; String javaProc, halProc; volatile Thread tMonitor; int period; public SvcMonitor() {}; @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent == null) { stopSelf(); return 0; } Log.d(TAG, "Starting SvcMonitor"); if ("stop".equals(intent.getAction())) { stopService(); } else if ("start".equals(intent.getAction())) { startMonitor(intent); } else if ("change".equals(intent.getAction())) { changeConfig(intent); } else { Log.d(TAG, "unknown action: + " + intent.getAction()); } return 0; } private void changeConfig(Intent intent) { if (tMonitor == null) { Log.d(TAG, "Service not active. Start service first"); return; } stopThread(); startMonitor(intent); } private void startMonitor(Intent intent) { if (tMonitor != null) { Log.d(TAG, "thread already active"); return; } javaProc = intent.getStringExtra("java"); halProc = intent.getStringExtra("hal"); period = intent.getIntExtra("period", 1000); if (javaProc == null || halProc == null || period < 100) { Log.d(TAG, "Failed starting monitor, invalid arguments."); stopSelf(); return; } Runnable monitor = new MonitorRunnable(this); tMonitor = new Thread(monitor); tMonitor.start(); } private void stopService() { stopThread(); stopSelf(); Log.d(TAG, "SvcMonitor stopped"); } private void stopThread() { if (tMonitor == null) { Log.d(TAG, "no active thread"); return; } Log.d(TAG, "interrupting monitor thread"); tMonitor.interrupt(); try { tMonitor.join(); } catch (InterruptedException e) { Log.d(TAG, "Unable to finish monitor thread"); } tMonitor = null; } @Override public void onDestroy() { super.onDestroy(); } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } public static class MonitorRunnable implements Runnable { long java_time_old, hal_time_old, cpu_time_old = -1; String javaPID, halPID; SvcMonitor svcmonitor; static String javaProcTAG; int period; public MonitorRunnable(SvcMonitor svcmonitor) { this.svcmonitor = svcmonitor; this.period = svcmonitor.period; javaPID = getPIDof(svcmonitor.javaProc); halPID = getPIDof(svcmonitor.halProc); java_time_old = getPsTime(javaPID); hal_time_old = getPsTime(halPID); cpu_time_old = getPsTime(""); javaProcTAG = String.valueOf(svcmonitor.javaProc.toCharArray()); } @Override public void run() { if (halPID.isEmpty() || javaPID.isEmpty()) { Log.d(javaProcTAG, "No such process: " + (halPID.isEmpty() ? svcmonitor.halProc : svcmonitor.javaProc)); return; } while (!Thread.interrupted()) { calculateUsage(); SystemClock.sleep(period); } Log.d(TAG, "Stopping monitor thread"); } private void calculateUsage() { long java_time = getPsTime(javaPID); long hal_time = getPsTime(halPID); long cpu_time = getPsTime(""); if (cpu_time_old >= 0) { float java_diff = (float) (java_time - java_time_old); float hal_diff = (float) (hal_time - hal_time_old); float cpu_diff = (float) (cpu_time - cpu_time_old); Log.w(javaProcTAG, "\n----------------\n"); Log.w(javaProcTAG, "JAVA level CPU: " + (java_diff * 100.0 / cpu_diff) + "%\n"); Log.w(javaProcTAG, " HAL level CPU: " + (hal_diff * 100.0 / cpu_diff) + "%\n"); Log.w(javaProcTAG, " SYS level CPU: " + ((java_diff + hal_diff) * 100.0 / cpu_diff) + "%\n"); } else { Log.w(TAG, "Waiting for status\n"); } java_time_old = java_time; hal_time_old = hal_time; cpu_time_old = cpu_time; } private String getPIDof(String psName) { String pid = ""; try { String[] cmd = {"/system/bin/sh", "-c", "ps | grep " + psName}; Process ps = Runtime.getRuntime().exec(cmd); BufferedReader in = new BufferedReader( new InputStreamReader(ps.getInputStream())); String temp = in.readLine(); if (temp == null || temp.isEmpty()) throw new IOException("No such process: " + psName); pid = temp.split(" +")[1]; in.close(); } catch (IOException e) { Log.d(javaProcTAG, "Error finding PID of process: " + psName + "\n", e); } return pid; } private long getPsTime(String pid) { String psStat = getPsStat("/" + pid); String[] statBreakDown = psStat.split(" +"); long psTime; if (pid.isEmpty()) { psTime = Long.parseLong(statBreakDown[1]) + Long.parseLong(statBreakDown[2]) + Long.parseLong(statBreakDown[3]) + Long.parseLong(statBreakDown[4]); } else { psTime = Long.parseLong(statBreakDown[13]) + Long.parseLong(statBreakDown[14]); } return psTime; } private String getPsStat(String psname) { String stat = ""; try { FileInputStream fs = new FileInputStream("/proc" + psname + "/stat"); BufferedReader br = new BufferedReader(new InputStreamReader(fs)); stat = br.readLine(); fs.close(); } catch (IOException e) { Log.d(TAG, "Error retreiving stat. \n"); } return stat; } } }