public class CPUusage extends Service
{
/** Name of the service used for logging */
private static final String TAG = "SystemSensService";
/** Version of the JSON records */
private static final String VER = "1.4";
/** Types of messages used by this service */
private static final int USAGESTAT_MSG = 1;
private static final int UPLOAD_START_MSG = 2;
private static final int UPLOAD_END_MSG = 3;
private static final int BATHIST_MSG = 4;
private static final int PROC_MSG = 5;
/** String names of JSON records */
private static final String USAGESTAT_TYPE = "usage";
private static final String NETTRANS_TYPE = "transmission";
private static final String NETRECV_TYPE = "receive";
private static final String CPUSTAT_TYPE = "cpu";
private static final String GPSSTAT_TYPE = "gps";
private static final String SENSORSTAT_TYPE = "sensor";
private static final String BATTERY_TYPE = "battery";
private static final String SCREEN_TYPE = "screen";
private static final String NET_TYPE = "network";
private static final String CALL_TYPE = "call";
private static final String SYSTEMSENS_TYPE = "systemsens";
private static final String NETDEV_TYPE = "netdev";
/** Intervals used for timers in seconds */
private long USAGESTAT_INTERVAL;
private long BATHIST_INTERVAL;
private long PROC_INTERVAL;
/** Default values for timers in seconds */
private static final long DEFAULT_USAGESTAT_INTERVAL = 120000;
private static final long DEFAULT_BATHIST_INTERVAL = 120000;
private static final long DEFAULT_PROC_INTERVAL = 120000;
/** Power manager object used to acquire a partial wakeLock */
private PowerManager m_PM;
/** WakeLock object */
private PowerManager.WakeLock m_WL;
/** State variable set when a worker thread starts uploading */
private boolean mIsUploading;
/** Usage statistics object */
private Usage mUsageStat;
/** Battery History object */
private History mHistoryStat;
/** Proc object */
private Proc mProc;
/** Uploader Object */
//private SystemSensUploader mUploader;
/** Dumper Object -- used for debugging */
private SystemSensDumper mDumper;
/** Database adaptor object */
private SystemSensDbAdaptor mDbAdaptor;
/** Holds the IMEI of the device */
private String IMEI;
/** telephonyManager object */
private TelephonyManager telManager;
//private SystemSensLogger logger;
/** Battery information record for reporting to the activity */
private JSONObject batteryJson;
/**
* Class for clients to access. Because we know this service always
* runs in the same process as its clients, we don't need to deal with
* IPC.
*/
public class LocalBinder extends Binder {
CPUusage getService() {
return CPUusage.this;
}
}
@Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
Log.v(TAG, "onStart");
}
@Override
public void onCreate() {
super.onCreate();
Log.v(TAG, "onCreate");
// Set the default intervals for USAGE and BATHIST counters
USAGESTAT_INTERVAL = DEFAULT_USAGESTAT_INTERVAL;
BATHIST_INTERVAL = DEFAULT_BATHIST_INTERVAL;
PROC_INTERVAL = DEFAULT_PROC_INTERVAL;
/* This object is used to log call durations */
telManager =
(TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
this.IMEI = telManager.getDeviceId();
mIsUploading = false;
mDbAdaptor = new SystemSensDbAdaptor(this);
//mUploader = new SystemSensUploader(mDbAdaptor);
mDumper = new SystemSensDumper(mDbAdaptor, this);
mUsageStat = new Usage();
mHistoryStat = new History(this);
mProc = new Proc();
try
{
mDbAdaptor.open();
}
catch (SQLException e)
{
Log.e(TAG, "Exception", e);
}
// Register for battery updates
// registerReceiver(mBatteryInfoReceiver, new IntentFilter(
// Intent.ACTION_BATTERY_CHANGED));
// Register for screen updates
/* registerReceiver(mScreenInfoReceiver , new IntentFilter(
Intent.ACTION_SCREEN_OFF));
registerReceiver(mScreenInfoReceiver , new IntentFilter(
Intent.ACTION_SCREEN_ON));*/
// Register for WiFi state changes
IntentFilter netIntentFilter = new IntentFilter();
netIntentFilter.addAction(
WifiManager.NETWORK_STATE_CHANGED_ACTION);
netIntentFilter.addAction(
WifiManager.WIFI_STATE_CHANGED_ACTION);
registerReceiver(mNetInfoReceiver, netIntentFilter);
// Register for call intents
// IntentFilter callIntentFilter = new IntentFilter();
//callIntentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
// registerReceiver(mCallInfoReceiver, callIntentFilter);
// Register for keyboard events
//IntentFilter keyboardIntentFilter = new IntentFilter();
//keyboardIntentFilter.addAction(KeyEvent.ACTION_DOWN);
//keyboardIntentFilter.addAction(KeyEvent.ACTION_UP);
//registerReceiver(mKeyboardReceiver, keyboardIntentFilter);
// Start getting process information
Message msg1 = mHandler.obtainMessage(USAGESTAT_MSG);
long nextTime = SystemClock.uptimeMillis()
+ USAGESTAT_INTERVAL;
mHandler.sendMessageAtTime(msg1, nextTime);
// Start getting process information
Message msg2 = mHandler.obtainMessage(BATHIST_MSG);
nextTime = SystemClock.uptimeMillis()
+ BATHIST_INTERVAL;
mHandler.sendMessageAtTime(msg2, nextTime);
// Start getting network device information
Message msg3 = mHandler.obtainMessage(PROC_MSG);
nextTime = SystemClock.uptimeMillis()
+ PROC_INTERVAL;
mHandler.sendMessageAtTime(msg3, nextTime);
// Log a message indicating starting SystemSens
JSONObject sysJson = new JSONObject();
try
{
sysJson.put("state", "started");
}
catch (JSONException e)
{
Log.e(TAG, "Exception", e);
}
// Acquire a partial wake lock
m_PM = (PowerManager) getSystemService(Context.POWER_SERVICE);
m_WL = m_PM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"SystemSense");
m_WL.acquire();
mDbAdaptor.createEntry( constructDataRecord(
sysJson, SYSTEMSENS_TYPE));
}
@Override
public void onDestroy() {
// Clear the message handler's pending messages
mHandler.removeMessages(USAGESTAT_MSG);
mHandler.removeMessages(BATHIST_MSG);
// unregisterReceiver(mBatteryInfoReceiver);
mDbAdaptor.close();
// Log a message indicating killing SystemSens
JSONObject sysJson = new JSONObject();
try
{
sysJson.put("state", "killed");
}
catch (JSONException e)
{
Log.e(TAG, "Exception", e);
}
mDbAdaptor.createEntry( constructDataRecord(
sysJson, SYSTEMSENS_TYPE));
m_WL.release();
Log.i(TAG, "Killed");
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** This is the object that receives interactions from clients. */
private final IBinder mBinder = new LocalBinder();
/**
* Broadcast receiver for WiFi updates.
* An object of this class has been passed to the system through
* registerReceiver.
*
*/
private BroadcastReceiver mNetInfoReceiver = new
BroadcastReceiver()
{
/**
* Method called whenever the intent is received.
* Gets the following information regarding the network
* connectivity:
* Network state change
*
*/
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
NetworkInfo netInfo;
String state = " ";
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
{
netInfo = (NetworkInfo) intent.getParcelableExtra
(WifiManager.EXTRA_NETWORK_INFO);
state = netInfo.getDetailedState().toString();
JSONObject netJson = new JSONObject();
}
else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION))
{
int wifiState = (int) intent.getIntExtra
(WifiManager.EXTRA_WIFI_STATE, 0);
switch (wifiState)
{
case WifiManager.WIFI_STATE_DISABLED:
state = "DISABLED";
break;
case WifiManager.WIFI_STATE_DISABLING:
state = "DISABLING";
break;
case WifiManager.WIFI_STATE_ENABLED:
state = "ENABLED";
break;
case WifiManager.WIFI_STATE_ENABLING:
state = "ENABLING";
break;
case WifiManager.WIFI_STATE_UNKNOWN:
default:
state = "UNKNOWN";
}
}
JSONObject netJson = new JSONObject();
try
{
netJson.put("state", state);
}
catch (JSONException e)
{
Log.e(TAG, "Exception", e);
}
mDbAdaptor.createEntry( constructDataRecord(
netJson, NET_TYPE));
}
};
/**
* Broadcast receiver for Battery information updates.
* An object of this class has been passed to the system through
* registerReceiver.
*
*/
private final Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
/* Get usage stat */
if (msg.what == USAGESTAT_MSG)
{
// DEBUG
//Log.i(TAG, "Received MSG" + msg.toString());
// Get system information here and insert to database
HashMap usageMap = mUsageStat.getStat();
mDbAdaptor.createEntry( constructDataRecord(
new JSONObject(usageMap),
USAGESTAT_TYPE));
// Schedule a new timer
msg = obtainMessage(USAGESTAT_MSG);
long nextTime = SystemClock.uptimeMillis()
+ USAGESTAT_INTERVAL;
sendMessageAtTime(msg, nextTime);
}
if (msg.what == BATHIST_MSG)
{
// Get send and receive information and insert to database
mHistoryStat.update();
JSONObject sentMap = mHistoryStat.getSentInfo();
JSONObject recvMap = mHistoryStat.getRecvInfo();
JSONObject cpuMap = mHistoryStat.getCpuInfo();
mDbAdaptor.createEntry( constructDataRecord(
sentMap,
NETTRANS_TYPE));
mDbAdaptor.createEntry( constructDataRecord(
recvMap,
NETRECV_TYPE));
mDbAdaptor.createEntry( constructDataRecord(
cpuMap,
CPUSTAT_TYPE));
// Schedule a new timer
msg = obtainMessage(BATHIST_MSG);
long nextTime = SystemClock.uptimeMillis()
+ BATHIST_INTERVAL;
sendMessageAtTime(msg, nextTime);
}
if (msg.what == PROC_MSG)
{
JSONObject netDev = mProc.getNetDev();
mDbAdaptor.createEntry( constructDataRecord(
netDev,
NETDEV_TYPE));
// Schedule a new timer
msg = obtainMessage(PROC_MSG);
long nextTime = SystemClock.uptimeMillis()
+ PROC_INTERVAL;
sendMessageAtTime(msg, nextTime);
}
if (msg.what == UPLOAD_START_MSG)
{
mIsUploading = true;
}
if (msg.what == UPLOAD_END_MSG)
{
mIsUploading = false;
}
}
// mDbAdaptor.fetchAllEntries();
};
/** Format a number of tenths-units as a decimal string without using a
* conversion to float. E.g. 347 -> "34.7"
*
* @param????????intVal
* @return????????String representing the decimal
*/
private final String tenthsToFixedString(int intVal) {
int tens = intVal / 10;
return new String("" + tens + "." + (intVal - 10*tens));
}
public JSONObject getBatteryInfo()
{
return batteryJson;
}
public String getHistInfo()
{
mHistoryStat.update();
String result = "CPU: " + mHistoryStat.getCpuInfo().toString();
result += "\nRecv: " + mHistoryStat.getRecvInfo().toString()
+ "\nSent: " + mHistoryStat.getSentInfo().toString();
mHistoryStat.update();
// String result = "GPS: " + mHistoryStat.getGpsInfo().toString();
return result;
}
/**
* Constructs a data record JSON object with the given JSONObject
* as the data field and the given type as the type field. Returns
* the string representation of this new object.
*
* @param data JSONObject to be used for the data field
* @param type String to be used for the type field
*/
private String constructDataRecord(JSONObject data, String type)
{
JSONObject dataRecord = new JSONObject();
// First thing, get the current time
final Calendar c = Calendar.getInstance();
String timeStr = "" +
c.get(Calendar.YEAR) + "-" +
c.get(Calendar.MONTH) + "-" +
c.get(Calendar.DAY_OF_MONTH) + " " +
c.get(Calendar.HOUR_OF_DAY) + ":" +
c.get(Calendar.MINUTE) + ":" +
c.get(Calendar.SECOND);
try
{
dataRecord.put("date", timeStr);
dataRecord.put("time_stamp", c.getTimeInMillis());
dataRecord.put("user", IMEI);
dataRecord.put("type", type);
dataRecord.put("ver", VER);
dataRecord.put("data", data);
}
catch (JSONException e)
{
Log.e(TAG, "Exception", e);
}
return dataRecord.toString();
}
/**
* Spawns a worker thread to "try" to write the contents of the
* database in a flat file.
* Before starting the thread, checks if a worker thread is
* already trying to dump. If so, returns. Otherwise a new
* thread is spawned and tasked with the dump job.
*
* This should only be used for debugging. It should NOT be used
* along with the upload method. Either dump() or upload() should
* be called.
*
*/
private void dump()
{
if (!mIsUploading)
{
Thread uploaderThread = new Thread()
{
public void run()
{
// Send an immediate message to the main thread
// to inform that a worker thread is running.
mHandler.sendMessageAtTime( mHandler.obtainMessage(
UPLOAD_START_MSG),
SystemClock.uptimeMillis());
Log.i(TAG, "Worker thread started dump task");
mDumper.tryDump();
// Send an immediate message to the main thread to
// inform that the worker thread is finished.
mHandler.sendMessageAtTime( mHandler.obtainMessage(
UPLOAD_END_MSG),
SystemClock.uptimeMillis());
}
};
uploaderThread.start();
}
else
{
Log.i(TAG, "Dump in progress ...");
}
}
}