lineage-sdk: Fix traffic stats for tethering and vpn use cases

Problems with current TrafficStats.getTotal[RT]XBytes()
implementation:

* Tethering related traffic is not counted at all.

* If you have a VPN active, stats are double counted.

So change the approach and track traffic on all non-VPN Internet
capable networks since:

* Tethering traffic is included in interface specific stats
  (unlike getTotal*).

* VPN networks are excluded so no longer double counted.

* Works correctly regardless of hotspot "Allow clients to use
  VPNs" hotspot setting.

* Works with simultaneous wifi ap and wifi upstream.
  (WIFI_HIDL_FEATURE_DUAL_INTERFACE = true)

Change-Id: Ic1135f10388b5be427202b092acd1444f94bd2b6
This commit is contained in:
Sam Mortimer
2019-08-24 00:41:12 -07:00
parent 9b69fd9c0c
commit 453cab629f

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2017-2018 The LineageOS project
* Copyright (C) 2017-2019 The LineageOS project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,10 @@ import android.graphics.drawable.Drawable;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TrafficStats;
import android.os.Handler;
import android.os.UserHandle;
@@ -43,9 +47,13 @@ import lineageos.providers.LineageSettings;
import org.lineageos.platform.internal.R;
import java.util.HashMap;
public class NetworkTraffic extends TextView {
private static final String TAG = "NetworkTraffic";
private static final boolean DEBUG = false;
private static final int MODE_DISABLED = 0;
private static final int MODE_UPSTREAM_ONLY = 1;
private static final int MODE_DOWNSTREAM_ONLY = 2;
@@ -71,8 +79,8 @@ public class NetworkTraffic extends TextView {
private boolean mNetworkTrafficIsVisible;
private long mTxKbps;
private long mRxKbps;
private long mLastTxBytesTotal;
private long mLastRxBytesTotal;
private long mLastTxBytes;
private long mLastRxBytes;
private long mLastUpdateTime;
private int mTextSizeSingle;
private int mTextSizeMulti;
@@ -86,6 +94,22 @@ public class NetworkTraffic extends TextView {
private SettingsObserver mObserver;
private Drawable mDrawable;
// Network tracking related variables
final private ConnectivityManager mConnectivityManager;
final private HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
private boolean mNetworksChanged = true;
public class NetworkState {
public NetworkCapabilities mNetworkCapabilities;
public LinkProperties mLinkProperties;
public NetworkState(NetworkCapabilities networkCapabilities,
LinkProperties linkProperties) {
mNetworkCapabilities = networkCapabilities;
mLinkProperties = linkProperties;
}
};
public NetworkTraffic(Context context) {
this(context, null);
}
@@ -104,6 +128,13 @@ public class NetworkTraffic extends TextView {
mNetworkTrafficIsVisible = false;
mObserver = new SettingsObserver(mTrafficHandler);
mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
final NetworkRequest request = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
mConnectivityManager.registerNetworkCallback(request, mNetworkCallback);
}
private LineageStatusBarItem.DarkReceiver mDarkReceiver =
@@ -154,18 +185,40 @@ public class NetworkTraffic extends TextView {
private Handler mTrafficHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
long now = SystemClock.elapsedRealtime();
long timeDelta = now - mLastUpdateTime;
final long now = SystemClock.elapsedRealtime();
final long timeDelta = now - mLastUpdateTime; /* ms */
if (msg.what == MESSAGE_TYPE_PERIODIC_REFRESH
&& timeDelta >= REFRESH_INTERVAL * 0.95f) {
// Update counters
long txBytes = 0;
long rxBytes = 0;
// Sum stats from interfaces of interest
for (NetworkState state : mNetworkMap.values()) {
final String iface = state.mLinkProperties.getInterfaceName();
if (iface == null) {
continue;
}
if (DEBUG) {
Log.d(TAG, "adding stats from interface " + iface);
}
txBytes += TrafficStats.getTxBytes(iface);
rxBytes += TrafficStats.getRxBytes(iface);
}
final long txBytesDelta = txBytes - mLastTxBytes;
final long rxBytesDelta = rxBytes - mLastRxBytes;
if (!mNetworksChanged && timeDelta > 0 && txBytesDelta >= 0 && rxBytesDelta >= 0) {
mTxKbps = (long) (txBytesDelta * 8f / 1000f / (timeDelta / 1000f));
mRxKbps = (long) (rxBytesDelta * 8f / 1000f / (timeDelta / 1000f));
} else if (mNetworksChanged) {
mTxKbps = 0;
mRxKbps = 0;
mNetworksChanged = false;
}
mLastTxBytes = txBytes;
mLastRxBytes = rxBytes;
mLastUpdateTime = now;
long txBytes = TrafficStats.getTotalTxBytes() - mLastTxBytesTotal;
long rxBytes = TrafficStats.getTotalRxBytes() - mLastRxBytesTotal;
mTxKbps = (long) (txBytes * 8f / (timeDelta / 1000f) / 1000f);
mRxKbps = (long) (rxBytes * 8f / (timeDelta / 1000f) / 1000f);
mLastTxBytesTotal += txBytes;
mLastRxBytesTotal += rxBytes;
}
final boolean enabled = mMode != MODE_DISABLED && isConnectionAvailable();
@@ -366,4 +419,41 @@ public class NetworkTraffic extends TextView {
mDrawable.setColorFilter(mIconTint, PorterDuff.Mode.MULTIPLY);
}
}
private ConnectivityManager.NetworkCallback mNetworkCallback =
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
mNetworkMap.put(network,
new NetworkState(mConnectivityManager.getNetworkCapabilities(network),
mConnectivityManager.getLinkProperties(network)));
mNetworksChanged = true;
}
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {
if (mNetworkMap.containsKey(network)) {
mNetworkMap.put(network, new NetworkState(networkCapabilities,
mConnectivityManager.getLinkProperties(network)));
mNetworksChanged = true;
}
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
if (mNetworkMap.containsKey(network)) {
mNetworkMap.put(network,
new NetworkState(mConnectivityManager.getNetworkCapabilities(network),
linkProperties));
mNetworksChanged = true;
}
}
@Override
public void onLost(Network network) {
mNetworkMap.remove(network);
mNetworksChanged = true;
}
};
}