Can someone explain how TrafficStats works its magic in the Android OS?
android
Solution
Here's a working, modified version of the code above. This one is using `RandomAccessFile` and doesn't rely on custom `imports` but uses only built-in `String` functions with their `Exceptions`.
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import android.util.Log;
public class TrafficStatsFile {
private static final String mobileRxFile_1 = "/sys/class/net/rmnet0/statistics/rx_bytes";
private static final String mobileRxFile_2 = "/sys/class/net/ppp0/statistics/rx_bytes";
private static final String mobileTxFile_1 = "/sys/class/net/rmnet0/statistics/tx_bytes";
private static final String mobileTxFile_2 = "/sys/class/net/ppp0/statistics/tx_bytes";
private static final String LOGGING_TAG = TrafficStatsFile.class.getSimpleName();
public long getMobileRxBytes() {
return tryBoth(mobileRxFile_1, mobileRxFile_2);
}
public long getMobileTxBytes() {
return tryBoth(mobileTxFile_1, mobileTxFile_2);
}
// Return the number from the first file which exists and contains data
private static long tryBoth(String a, String b) {
long num = readNumber(a);
return num >= 0 ? num : readNumber(b);
}
// Returns an ASCII decimal number read from the specified file, -1 on error.
private static long readNumber(String filename) {
try {
RandomAccessFile f = new RandomAccessFile(filename, "r");
try {
Log.d(LOGGING_TAG, "f.length() = " + f.length());
String contents = f.readLine();
if(!contents.isEmpty() && contents!=null) {
try {
return Long.parseLong(contents);
}
catch(NumberFormatException nfex) {
Log.w(LOGGING_TAG, "File contents are not numeric: " + filename);
}
}
else {
Log.w(LOGGING_TAG, "File contents are empty: " + filename);
}
}
catch (FileNotFoundException fnfex) {
Log.w(LOGGING_TAG, "File not found: " + filename, fnfex);
}
catch(IOException ioex) {
Log.w(LOGGING_TAG, "IOException: " + filename, ioex);
}
}catch(FileNotFoundException ffe){
Log.w(LOGGING_TAG, "File not found: " + filename, ffe);
}
return -1;
}
}
Problem
I've written a nice little Android app to check data usage, unfortunately it relies heavily on android.net.TrafficStats which was introduced with Froyo (Android 2.2). I'm attempting to back-port this class for my non-Froyo users, and what I'm able to determine from the Android source is: - TrafficStats.java is just a native pointer to a c file - The c file opens two files (see below) and reads their contents - If either contains a numeric value it spits it back as the "bytes used" count Here's my challenge... when I call TrafficStats via the API on my device, I get a reading (ex. 1113853 bytes). When I open the two files and check their contents, one file doesn't exist and the other file is 0 bytes. So clearly I mis-understood what TrafficStats is doing. Can anyone shed some light on how it's working it's magic? Thanks for the help. (here is my attempt to port the c file to java) ``` package com.suttco.net; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import com.suttco.IOUtils; import com.suttco.StringUtils; import android.util.Log; public class TrafficStatsFile { private static final String mobileRxFile_1 = "/sys/class/net/rmnet0/statistics/rx_bytes"; private static final String mobileRxFile_2 = "/sys/class/net/ppp0/statistics/rx_bytes"; private static final String mobileTxFile_1 = "/sys/class/net/rmnet0/statistics/tx_bytes"; private static final String mobileTxFile_2 = "/sys/class/net/ppp0/statistics/tx_bytes"; private static final String LOGGING_TAG = TrafficStatsFile.class.getSimpleName(); public long getMobileRxBytes() { return tryBoth(mobileRxFile_1, mobileRxFile_2); } public long getMobileTxBytes() { return tryBoth(mobileTxFile_1, mobileTxFile_2); } // Return the number from the first file which exists and contains data private static long tryBoth(String a, String b) { long num = readNumber(a); return num >= 0 ? num : readNumber(b); } // Returns an ASCII decimal number read from the specified file, -1 on error. private static long readNumber(String filename) { File f = new File(filename); if(f.exists()) { if(f.canRead()) { try { Log.d(LOGGING_TAG, "f.length() = " + f.length()); String contents = IOUtils.readFileAsString(f); if(StringUtils.IsNotNullOrEmpty(contents)) { try { return Long.parseLong(contents); } catch(NumberFormatException nfex) { Log.w(LOGGING_TAG, "File contents are not numeric: " + filename); } } else { Log.w(LOGGING_TAG, "File contents are empty: " + filename); } } catch (FileNotFoundException fnfex) { Log.w(LOGGING_TAG, "File not found: " + filename, fnfex); } catch(IOException ioex) { Log.w(LOGGING_TAG, "IOException: " + filename, ioex); } } else { Log.w(LOGGING_TAG, "Unable to read file: " + filename); } } else { Log.w(LOGGING_TAG, "File does not exist: " + filename); } return -1; } } ```