android TrafficStats getUidRxBytes inaccurate

2020-03-26 04:56发布

问题:

I write a little android app, sends Http request, receives response from server, and count how many bytes transmitted and received. and the code is simply as follow

long receivedBytes = TrafficStats.getUidRxBytes(uid)-lastNumer

i find that the receivedBytes is always larger the size http Header+http Body, for example the actual http frame's size i caught( use wireshark) in server is 1645 bytes(header+body), but the android API returns receivedBytes is 1912, so as the transmission.

the TrafficStats getUidRxBytes itself is inaccurate(may be this problem is specific to my platform samsung i9300 with cynogenmod 10.3)

finally, i find the correct way to count the data usage i find other way to count the data usage which seems more accurate than TrafficStats API.(many thanks to here)

private long[] getStat() {
    String line, line2;
    long[] stats = new long[2];
    try {
        File fileSnd = new File("/proc/uid_stat/"+uid+"/tcp_snd");
        File fileRcv = new File ("/proc/uid_stat/"+uid+"/tcp_rcv");
        BufferedReader br1 = new BufferedReader(new FileReader(fileSnd));
        BufferedReader br2 = new BufferedReader(new FileReader(fileRcv));
        while ((line = br1.readLine()) != null&& (line2 = br2.readLine()) != null) {
            stats[0] = Long.parseLong(line);
            stats[1] = Long.parseLong(line2);
        }
        br1.close();
        br2.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return stats;
}

回答1:

I see that you've already found a solution, but I'll add my thoughts on your question as it might be useful to other people (ended up here myself after googling how to use the TrafficStats API).

The API documentation states:

Statistics are measured at the network layer, so they include both TCP and UDP usage.

The documentation could indeed be more thorough, but I'm inclined to say that one can assume that the returned byte count also includes the bytes making up the transport layer header and the network layer header.

HTTP is an application layer protocol. When you're calculating your expected bytes to be the HTTP header bytes plus the HTTP body bytes, you're only dealing with application layer bytes, hence not accounting for transport and network layer header bytes. I assume TCP is used for the download. This adds a header ranging from 20 to 60 bytes. Moreover, let's assume you're using IPv4 for the download. This also adds a header ranging from 20 to 60 bytes.

Obviously this won't account for the entire 1912 - 1645 = 267 bytes, but it might give you/other people some leads.


A bit off-topic, but still related. It's not quite clear if the TrafficStats API actually count header bytes or not. According to this answer, the API does not count header bytes. However, given the API documentation listed above, the linked answer may be stipulating something that is not true (at least not for API level 21). Moreover, this question also hints at TrafficStats actually counting network and transport layer header bytes (check comments).


TrafficStats actually counts network and transport layer header bytes. See kernel source and TrafficStatsTest.



回答2:

From my understanding, you should combine getUidRxBytes with getUidRxPackets.

You should have something like : getUidRxBytes = getUidRxPackets * (tcp/ip header size)