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:
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user