NetworkTraffic: Include tethering hw offload statistics

*) Regular interface stats don't include hw offload tethering
   statistics so collect and include them in our traffic
   calculations.

Change-Id: Id72577429840f65ae20d7b80e7490ec41d826579
This commit is contained in:
Sam Mortimer
2019-09-09 21:53:40 -07:00
committed by Bruno Martins
parent c3b5589ccf
commit f12a1e5568

View File

@@ -32,11 +32,15 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkStats;
import android.net.TrafficStats;
import android.os.Handler;
import android.os.UserHandle;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -97,6 +101,8 @@ public class NetworkTraffic extends TextView {
// Network tracking related variables
final private ConnectivityManager mConnectivityManager;
final private HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
// Used to indicate that the set of sources contributing
// to current stats have changed.
private boolean mNetworksChanged = true;
public class NetworkState {
@@ -110,6 +116,8 @@ public class NetworkTraffic extends TextView {
}
};
private INetworkManagementService mNetworkManagementService;
public NetworkTraffic(Context context) {
this(context, null);
}
@@ -121,6 +129,9 @@ public class NetworkTraffic extends TextView {
public NetworkTraffic(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mNetworkManagementService = INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
final Resources resources = getResources();
mTextSizeSingle = resources.getDimensionPixelSize(R.dimen.net_traffic_single_text_size);
mTextSizeMulti = resources.getDimensionPixelSize(R.dimen.net_traffic_multi_text_size);
@@ -189,20 +200,35 @@ public class NetworkTraffic extends TextView {
final long timeDelta = now - mLastUpdateTime; /* ms */
if (msg.what == MESSAGE_TYPE_PERIODIC_REFRESH
&& timeDelta >= REFRESH_INTERVAL * 0.95f) {
// Update counters
// Sum tx and rx bytes from all sources of interest
long txBytes = 0;
long rxBytes = 0;
// Sum stats from interfaces of interest
// Add interface stats
for (NetworkState state : mNetworkMap.values()) {
final String iface = state.mLinkProperties.getInterfaceName();
if (iface == null) {
continue;
}
final long ifaceTxBytes = TrafficStats.getTxBytes(iface);
final long ifaceRxBytes = TrafficStats.getRxBytes(iface);
if (DEBUG) {
Log.d(TAG, "adding stats from interface " + iface);
Log.d(TAG, "adding stats from interface " + iface
+ " txbytes " + ifaceTxBytes + " rxbytes " + ifaceRxBytes);
}
txBytes += TrafficStats.getTxBytes(iface);
rxBytes += TrafficStats.getRxBytes(iface);
txBytes += ifaceTxBytes;
rxBytes += ifaceRxBytes;
}
// Add tether hw offload counters since these are
// not included in netd interface stats.
final TetheringStats tetheringStats = getOffloadTetheringStats();
txBytes += tetheringStats.txBytes;
rxBytes += tetheringStats.rxBytes;
if (DEBUG) {
Log.d(TAG, "mNetworksChanged = " + mNetworksChanged);
Log.d(TAG, "tether hw offload txBytes: " + tetheringStats.txBytes
+ " rxBytes: " + tetheringStats.rxBytes);
}
final long txBytesDelta = txBytes - mLastTxBytes;
@@ -350,6 +376,45 @@ public class NetworkTraffic extends TextView {
return cm.getActiveNetworkInfo() != null;
}
private class TetheringStats {
long txBytes;
long rxBytes;
}
private TetheringStats getOffloadTetheringStats() {
TetheringStats tetheringStats = new TetheringStats();
NetworkStats stats = null;
try {
// STATS_PER_UID returns hw offload and netd stats combined (as entry UID_TETHERING)
// STATS_PER_IFACE returns only hw offload stats (as entry UID_ALL)
stats = mNetworkManagementService.getNetworkStatsTethering(
NetworkStats.STATS_PER_IFACE);
} catch (RemoteException e) {
Log.e(TAG, "Unable to call getNetworkStatsTethering: " + e);
}
if (stats == null) {
// nothing we can do except return zero stats
return tetheringStats;
}
NetworkStats.Entry entry = null;
// Entries here are per tethered interface.
// Counters persist even after tethering has been disabled.
for (int i = 0; i < stats.size(); i++) {
entry = stats.getValues(i, entry);
if (DEBUG) {
Log.d(TAG, "tethering stats entry: " + entry);
}
// hw offload tether stats are reported under UID_ALL.
if (entry.uid == NetworkStats.UID_ALL) {
tetheringStats.txBytes += entry.txBytes;
tetheringStats.rxBytes += entry.rxBytes;
}
}
return tetheringStats;
}
private void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();