MonitorLog: Aplicativo para análise de Bateria no Android

On 2 de agosto de 2012 by Johnnatan Messias

Dispositivos móveis estão cada vez mais presentes no dia-a-dia das pessoas e com eles vem novos recursos para auxiliar nas tarefas cotidianas de cada usuário.

O Android, sistema operacional para dispositivos móveis do Google, veio realmente para ficar e com ele trazendo uma infinidade de recursos que até pouco tempo não era possíveis, recursos esses que já faz parte da nossa rotina.

Hoje, pequenos dispositivos que daremos o nome de smartphones possuem cada vez mais uma robustez em hardware de modo a deixar computadores pessoais de alguns anos atrás totalmente inviáveis. Sabe-se que quanto mais recursos e sensores esses dispositivos possuírem maior será o consumo de bateria, isso é fato. Como se investe muito em hardware e software e ao mesmo tempo devido ao avanço das baterias não acompanharem essa escala temporal o tempo de utilização desses dispositivos decairá drasticamente.

Pensando nisso, propomos uma implementação de um aplicativo, MonitorLog, para a leitura de alguns sensores de dispositivos Android a fim de usarmos dados para medir o gasto energético e consumo de tráfego da rede.

Alguns conceitos em Android:

  • Atividade: São simplesmente a tela que compõe a aplicação, sendo um processo ativo e visível ao usuário.
  • Serviço: Componente da aplicação capaz de execução em segundo plano, não fornecendo uma interface com o usuário.

Sendo assim, teremos as seguintes classes em Java que compõem o MonitorLog:

  • MonitorServiceInterface.java: Interface com os métodos que deverão obrigatoriamente serem implementados pelo serviço ou conexão do serviço.
  • MonitorService.java: O serviço do MonitorLog propriamente dito.
  • MonitorServiceConexao.java: Classe responsável por efetuar a conexão da atividade com o serviço bem como de utilidade para o usuário poder sobrescrever algum método contido no serviço MonitorService.java
  • MainActivity.java: Classe que compõe a atividade principal da aplicação.

Obs.: Para esse aplicativos implementamos o método execute() para salvar os dados no cartão de memória do dispositivo.

Abaixo podemos ver os métodos que serão implementados no serviço através da interface MonitorServiceInterface;

[sourcecode language=”java”]
package service.widget;
public interface MonitorServiceInterface {
public String getBatteryCapacity();
public String getBatteryStatus();
public String getDate();
public String getTimestamp();
public String getTaxaTotalTx();
public String getTaxaTotalRx();
public String getTaxaMobileTx();
public String getTaxaMobileRx();
public String getGPS();
public String getWiFiLinkSpeed();
public String getWiFiRSSI();
public String getAccelerometer();
public String getTypeNameConnection();
public long getTimeThread();
public void execute();
}
[/sourcecode]

Onde os métodos:

  • getBatteryCapacity(): Retorna a porcentagem de bateria contida no dispositivo.
  • getBatteryStatus(): Retorna se a bateria está sendo descarregada ou recarregada.
  • getDate(): Retorna a data.
  • getTimestamp(): Retorna o tempo em timestamp.
  • getTaxaTotalTx(): Retorna a quantidade de tráfego de todas as interfaces e redes para transmissão de dados.
  • getTaxaTotalRx(): Retorna a quantidade de tráfego de todas as interfaces e redes para recepção de dados.
  • getTaxaMobileTx(): Retorna a quantidade de tráfego de todas as interfaces de rede dados da telefonia móvel para transmissão de dados.
  • getTaxaMobileRx(): Retorna a quantidade de tráfego de todas as interfaces de rede dados da telefonia móvel para recepção de dados.
  • getGPS(): Retorna a latitude e longitude do sensor GPS do dispositivo.
  • getWiFiLinkSpeed(): Retorna a taxa de transferência de dados atual da WiFi.
  • getWiFiRSSI(): Retorna o RSSI da rede WiFi a qual o dispositivo está conectado.
  • getAccelerometer(): Retorna as coordenadas x, y, e z do acelerômetro.
  • getTypeNameConnection(): Retorna o tipo de conexão do dispositivo, ou seja, se é mediante WiFi ou Mobile (3G, EDGE, HSDPA).
  • getTimeThread(): Retorna o tempo em que a Thread ficará em espera.
  • execute(): Método principal do serviço que é o responsável pela execução da leitura dos dados dos métodos anteriores citados.

Código da classe responsável por realizar a conexão do serviço com a atividade, recuperando o acesso ao serviço mediante a interface MonitorServiceInterface.java

[sourcecode language=”java”]
package service;
public class MonitorServiceConexao extends MonitorService implements
MonitorServiceInterface {
private final IBinder conexao = new MonitorBinder();
public class MonitorBinder extends Binder {
public MonitorServiceInterface getService() {
return MonitorServiceConexao.this;
}
}

@Override
public IBinder onBind(Intent intent) {
return conexao;
}
}
[/sourcecode]

Através da MainActivity.java iniciamos tanto aplicação quanto o serviço. Essa classe compõe, ainda, uma tela para o usuário interagir com a atividade.

[sourcecode language=”java”]
package com.monitorlog;
public class MainActivity extends Activity implements ServiceConnection {
private MonitorServiceInterface monitorServiceInterface;
final ServiceConnection serviceConnection = this;
private static String TAG = "MainActivity";
private Button buttonStart, buttonStop;
private boolean isServiceRunning = false;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
buttonStart = (Button) findViewById(R.id.button_start);
buttonStop = (Button) findViewById(R.id.button_stop);
}

@Override
protected void onDestroy() {
super.onDestroy();
if (isServiceRunning) {
unbindService(serviceConnection);
Log.i(TAG, "Serviço finalizado");
Toast.makeText(this, "Seviço finalizado", Toast.LENGTH_SHORT)
.show();
}
}

public void onClickStartMyService(View v) {
bindService(new Intent(this, MonitorServiceConexao.class),
serviceConnection, Context.BIND_AUTO_CREATE);
buttonStart.setEnabled(false);
buttonStop.setEnabled(true);
isServiceRunning = true;
Log.i(TAG, "Serviço iniciado");
Toast.makeText(this, "Seviço iniciado", Toast.LENGTH_SHORT).show();
}

public void onClickStopMyService(View v) {
unbindService(serviceConnection);
buttonStart.setEnabled(true);
buttonStop.setEnabled(false);
isServiceRunning = false;
Log.i(TAG, "Serviço finalizado");
Toast.makeText(this, "Seviço finalizado", Toast.LENGTH_SHORT).show();
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MonitorBinder binder = (MonitorBinder) service;
monitorServiceInterface = binder.getService();
}

@Override
public void onServiceDisconnected(ComponentName name) {
monitorServiceInterface = null;
}
}
[/sourcecode]

Abaixo o código fonte do nosso serviço:

[sourcecode language=”java”]
package service;
public class MonitorService extends Service implements LocationListener,
SensorEventListener, Runnable {
private static String TAG = "MonitorService";
private SensorManager sensorManager;
private float x, y, z;
private Double coordenadasGPS[] = new Double[3];
private boolean active;
private long time = 1000;
private String path = "/sdcard/MonitorLog";
private String appName;
private String datas;
private String pathBatteryCapacity = "/sys/class/power_supply/battery/capacity";
private String pathBatteryStatus = "/sys/class/power_supply/battery/status";
private long inicialTaxaTotalTx = Long.parseLong(getTaxaTotalTx());
private long inicialTaxaTotalRx = Long.parseLong(getTaxaTotalRx());
private long inicialTaxaMobileTx = Long.parseLong(getTaxaMobileTx());
private long inicialTaxaMobileRx = Long.parseLong(getTaxaMobileRx());

@Override
public void onCreate() {
super.onCreate();
appName = "monitor" + getString(R.string.app_name) + ".txt";
active = true;
new Thread(this).start();
Log.i(TAG, "onCreate()");
}

@Override
public void onDestroy() {
super.onDestroy();
active = false;
Log.i(TAG, "onDestroy()");
}

@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}

@Override
public IBinder onBind(Intent intent) {
return null;
}

public void execute() {
PrintWriter outPut = null;
File file = new File(path);
file.mkdirs();
Log.i(TAG, "run()");
try {
outPut = new PrintWriter(new File(file.getPath(), appName));
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
}
outPut.println("timestamp;taxaTotalTx;taxaTotalRx;taxaMobileTx;"
+ "taxaMobileRx;wiFiLinkSpeed;wiFiRSSI;TypeNameConnection;"
+ "batteryCapacity;batteryStatus");
while (active) {
datas = getTimestamp() + ";" + getTaxaTotalTx() + ";"
+ getTaxaTotalRx() + ";" + getTaxaMobileTx() + ";"
+ getTaxaMobileRx() + ";" + getWiFiLinkSpeed() + ";"
+ getWiFiRSSI() + ";" + getTypeNameConnection() + ";"
+ getBatteryCapacity() + ";" + getBatteryStatus();
outPut.println(datas);
try {
Thread.sleep(getTimeThread());
} catch (InterruptedException e) {
Log.e(TAG, e.getMessage(), e);
}
}
outPut.close();
}

@Override
public void run() {
execute();
}

public long getTimeThread() {
return time;
}

public String getBatteryCapacity() {
String batteryCapacity = null;
Scanner scan = null;
try {
scan = new Scanner(new File(pathBatteryCapacity));
if (scan.hasNext()) {
batteryCapacity = scan.nextLine();
}
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage(), e);
}
scan.close();
Log.i(TAG, "getBatteryCapacity() = " + batteryCapacity);
return batteryCapacity;
}

public String getBatteryStatus() {
String batteryStatus = null;
Scanner scan = null;
try {
scan = new Scanner(new File(pathBatteryStatus));
if (scan.hasNext()) {
batteryStatus = scan.nextLine();
}
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage(), e);
}
scan.close();
Log.i(TAG, "getBatteryStatus() = " + batteryStatus);
return batteryStatus;
}

public String getDate() {
Date date = new Date();
String dateString = date.toString();
Log.i(TAG, "getDate() = " + dateString);
return dateString;
}

public String getTimestamp() {
Date date = new Date();
String dateTimestamp = String.valueOf(date.getTime() / 1000);
Log.i(TAG, "getTimestamp() = " + dateTimestamp);
return dateTimestamp;
}

public String getTaxaTotalTx() {
String taxaTotalTx = String.valueOf(TrafficStats.getTotalTxBytes()
– inicialTaxaTotalTx);
Log.i(TAG, "getTaxaTotalTx() = " + taxaTotalTx);
return taxaTotalTx;
}

public String getTaxaTotalRx() {
String taxaTotalRx = String.valueOf(TrafficStats.getTotalRxBytes()
– inicialTaxaTotalRx);
Log.i(TAG, "getTaxaTotalRx() = " + taxaTotalRx);
return taxaTotalRx;
}

public String getTaxaMobileTx() {
String taxaMobileTx = String.valueOf(TrafficStats.getMobileTxBytes()
– inicialTaxaMobileTx);
Log.i(TAG, "getTaxaMobileTx() = " + taxaMobileTx);
return taxaMobileTx;
}

public String getTaxaMobileRx() {
String taxaMobileRx = String.valueOf(TrafficStats.getMobileRxBytes()
– inicialTaxaMobileRx);
Log.i(TAG, "getTaxaMobileRx() = " + taxaMobileRx);
return taxaMobileRx;
}

public String getGPS() {
String gps = String.valueOf(coordenadasGPS[0]) + ";"
+ String.valueOf(coordenadasGPS[1]);
Log.i(TAG, "getGPS() = " + gps);
return gps;
}

public String getTypeNameConnection() {
ConnectivityManager connectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
String infoString = "Error";
if (connectivity != null) {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].isConnected()) {
infoString = info[i].getTypeName();
break;
}
}
}
}
Log.i(TAG, "getTypeNameConnection() = " + infoString);
return infoString;
}

public String getWiFiLinkSpeed() {
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String wiFiLinkSpeed = String.valueOf(wifiInfo.getLinkSpeed());
Log.i(TAG, "getWiFiLinkSpeed() = " + wiFiLinkSpeed);
return wiFiLinkSpeed;
}

public String getWiFiRSSI() {
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String wiFiRSSI = String.valueOf(wifiInfo.getRssi());
Log.i(TAG, "getWiFiRSSI() = " + wiFiRSSI);
return wiFiRSSI;
}

public void accelerometer() {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
Log.i(TAG, "accelerometer()");
}

public String getAccelerometer() {
String accelerometer = String.valueOf(x) + ";" + String.valueOf(y)
+ ";" + String.valueOf(z);
Log.i(TAG, "getAccelerometer() = " + accelerometer);
return accelerometer;
}

private void gps() {
Location loc = getLocationManager().getLastKnownLocation(
LocationManager.GPS_PROVIDER);
if (loc != null) {
coordenadasGPS[0] = loc.getLatitude();
coordenadasGPS[1] = loc.getLongitude();
Log.i("getLocationManager", "ultima localizacao: " + getGPS());
}
getLocationManager().requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);
Log.i(TAG, "gps()");
}

private LocationManager getLocationManager() {
Log.i(TAG, "getLocationManager()");
return (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
x = event.values[0];
y = event.values[1];
z = event.values[2];
}
}

public void onLocationChanged(Location location) {
coordenadasGPS[0] = location.getLatitude();
coordenadasGPS[1] = location.getLongitude();
Log.i("getLocationManager", "ultima localizacao: " + getGPS());
}

@Override
public void onProviderDisabled(String provider) {
}

@Override
public void onProviderEnabled(String provider) {
}

@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
[/sourcecode]

Tela da aplicação:


Conclusão: Através da implementação do MonitorLog podemos realizar um estudo com os dados obtidos de modo a melhorar o consumo de energia das aplicações desenvolvidas em Android. O próximo passo é criarmos cenários para o estudo propriamente dito.

Download:

  • Aplicativo (link)    
  • SourceCode (link

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *