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