/**
*
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*
*/
package edu.mit.media.funf.probe.builtin;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.os.Bundle;
import android.os.Debug.MemoryInfo;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import edu.mit.media.funf.Schedule;
import edu.mit.media.funf.Schedule.DefaultSchedule;
import edu.mit.media.funf.probe.Probe.Base;
import edu.mit.media.funf.util.LogUtil;
/**
* Reads various information from the /proc file system.
*
* Based on the SystemSens Proc Sensor, written by Hossein Falaki.
* @author Hossein Falaki
* @author Alan Gardner
*/
@Schedule.DefaultSchedule(interval=300)
public class ProcessStatisticsProbe extends Base {
/** Address of the network devices stat */
private static final String NETDEV_PATH = "/proc/net/dev";
/** Address of memory information file */
private static final String MEMINFO_PATH = "/proc/meminfo";
@Override
protected void onStart() {
ActivityManager am = (ActivityManager)getContext().getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
ArrayList<RunningAppProcessInfo> runningProcesses = new ArrayList<RunningAppProcessInfo>(am.getRunningAppProcesses());
final int numProcesses = runningProcesses.size();
int[] runningProcessIds = new int[numProcesses];
for (int i=0; i<numProcesses; i++ ) {
runningProcessIds[i] = runningProcesses.get(i).pid;
}
List<MemoryInfo> memoryInfos = Arrays.asList(am.getProcessMemoryInfo(runningProcessIds));
List<ProcessErrorStateInfo> errorInfos = am.getProcessesInErrorState();
Gson gson = getGson();
JsonObject data = new JsonObject();
data.add("RUNNING_PROCESS_INFO", gson.toJsonTree(runningProcesses));
data.add("RUNNING_PROCESS_MEMORY_INFO", gson.toJsonTree(memoryInfos));
data.add("ERRORED_PROCESS_INFO", gson.toJsonTree(errorInfos));
data.add("CPU_LOAD", gson.toJsonTree(getCpuLoad()));
data.add("MEM_INFO", gson.toJsonTree(getMemInfo()));
data.add("NET_DEV", gson.toJsonTree(getNetDev()));
sendData(data);
stop();
}
public Bundle getMemInfo()
{
Bundle result = new Bundle();
StringTokenizer linest;
String key, value;
try
{
BufferedReader reader = new BufferedReader( new
InputStreamReader( new FileInputStream( MEMINFO_PATH ) ), 2048 );
char[] buffer = new char[2024];
reader.read(buffer, 0, 2000);
StringTokenizer st = new StringTokenizer(
new String(buffer), "\n", false);
for (int i = 0; i < st.countTokens(); i++)
{
linest = new StringTokenizer(st.nextToken());
key = linest.nextToken();
value = linest.nextToken();
result.putLong(key, Long.valueOf(value));
}
reader.close();
}
catch (Exception e)
{
Log.e(LogUtil.TAG, "Exception parsing the file", e);
}
return result;
}
public ArrayList<Long> readProcessCpuTime(long processId)
{
ArrayList<Long> res = null;
long utime = 0;
long stime = 0;
String line;
String[] toks;
try
{
BufferedReader reader = new BufferedReader( new
InputStreamReader( new
FileInputStream(
"/proc/" + processId + "/stat")), 512);
while ( (line = reader.readLine()) != null )
{
toks = line.split(" ");
utime = Long.parseLong(toks[13]);
stime = Long.parseLong(toks[14]);
}
reader.close();
res = new ArrayList<Long>();
res.add(utime);
res.add(stime);
}
catch( IOException ex )
{
Log.e(LogUtil.TAG, "Could not read /proc file", ex);
}
return res;
}
public Bundle getCpuLoad()
{
Bundle result = new Bundle();
float totalUsage, userUsage, niceUsage, systemUsage;
Double cpuFreq = 0.0;
long sTotal = 0;
String line;
String[] toks;
String[] words;
try
{
BufferedReader reader = new BufferedReader( new
InputStreamReader( new
FileInputStream( "/proc/cpuinfo" ) ), 2048 );
while ( (line = reader.readLine()) != null )
{
toks = line.split(" ");
words = toks[0].split("\t");
if (words[0].equals("BogoMIPS"))
{
cpuFreq = Double.parseDouble(toks[1]);
}
}
reader.close();
}
catch (IOException ioe)
{
Log.e(LogUtil.TAG, "Exception parsing /proc/cpuinfo", ioe);
}
try
{
BufferedReader reader = new BufferedReader( new
InputStreamReader( new
FileInputStream( "/proc/stat" ) ), 2048 );
long idle = 0;
long user = 0;
long system = 0;
long nice = 0;
while ( (line = reader.readLine()) != null )
{
toks = line.split(" ");
if (toks[0].equals("cpu"))
{
long currUser, currNice, currSystem, currTotal,
currIdle;
Bundle cpuObject = new Bundle();
currUser = Long.parseLong(toks[2]);
currNice = Long.parseLong(toks[3]);
currSystem = Long.parseLong(toks[4]);
currTotal = currUser + currNice + currSystem;
currIdle = Long.parseLong(toks[5]);
totalUsage = (currTotal - sTotal) * 100.0f /
(currTotal - sTotal + currIdle - idle);
userUsage = (currUser - user) * 100.0f /
(currTotal - sTotal + currIdle - idle);
niceUsage = (currNice - nice) * 100.0f /
(currTotal - sTotal + currIdle - idle);
systemUsage = (currSystem - system) * 100.0f /
(currTotal - sTotal + currIdle - idle);
sTotal = currTotal;
idle = currIdle;
user = currUser;
nice = currNice;
system = currSystem;
// Update the Status Object
//Status.setCPU(totalUsage);
cpuObject.putFloat("total", totalUsage);
cpuObject.putFloat("user", userUsage);
cpuObject.putFloat("nice", niceUsage);
cpuObject.putFloat("system", systemUsage);
cpuObject.putDouble("freq", cpuFreq);
result.putBundle("cpu", cpuObject);
}
else if (toks[0].equals("ctxt"))
{
String ctxt = toks[1];
result.putLong("ContextSwitch", Long.valueOf(ctxt));
}
else if (toks[0].equals("btime"))
{
String btime = toks[1];
result.putLong("BootTime", Long.valueOf(btime));
}
else if (toks[0].equals("processes"))
{
String procs = toks[1];
result.putLong("Processes", Long.valueOf(procs));
}
}
result.putLong("CpuTotalTime", sTotal);
reader.close();
}
catch( IOException ex )
{
Log.e(LogUtil.TAG, "Could not read /proc file", ex);
}
return result;
}
/**
* Parses and returns the contents of /proc/net/dev.
* It first reads the content of the file in /proc/net/dev.
* This file contains a row for each network interface.
* Each row contains the number of bytes and packets that have
* been sent and received over that network interface. This method
* parses this file and returns a JSONObject that maps the network
* interface name to this information.
*
* @return JSONObject containing en entry for each
* physical interface.
*/
public Bundle getNetDev()
{
Bundle result = new Bundle();
Bundle data;
StringTokenizer linest;
String devName, recvBytes, recvPackets,
sentBytes, sentPackets;
try
{
BufferedReader reader = new BufferedReader( new
InputStreamReader( new FileInputStream( NETDEV_PATH ) ), 2048 );
char[] buffer = new char[2024];
reader.read(buffer, 0, 2000);
StringTokenizer st = new StringTokenizer(
new String(buffer), "\n", false);
//The first two lines of the file are headers
st.nextToken();
st.nextToken();
for (int j = 0; j < 5; j++)
{
linest = new StringTokenizer(st.nextToken());
devName = linest.nextToken();
recvBytes = linest.nextToken();
recvPackets = linest.nextToken();
// Skip six tokens
for (int i = 0; i < 6; i++)
linest.nextToken();
sentBytes = linest.nextToken();
sentPackets = linest.nextToken();
data = new Bundle();
data.putLong("RxBytes", Long.valueOf(recvBytes));
data.putLong("RxPackets", Long.valueOf(recvPackets));
data.putLong("TxBytes", Long.valueOf(sentBytes));
data.putLong("TxPackets", Long.valueOf(sentPackets));
result.putBundle(devName, data);
}
reader.close();
}
catch (Exception e)
{
Log.e(LogUtil.TAG, "Exception", e);
}
return result;
}
}