DO NOT MERGE: VPN network stat accounting changes.
Properly account for VPN apps that make heavy use of the tun
interface. Prior to this change a VPN app could be incorrectly charged
for more data than it actually used if it sent more traffic through
the tun interface than the underlying interface.
This change excludes VPN app traffic on the tun interface from the
adjustment pool and doesn't redistribute traffic to the VPN app.
Instead all of the redistributed traffic is deducted from the VPN app
which effectively represents any overhead incurred by the VPN app.
BUG: 30557871
(cherry picked from commit 12255e3655823ed56d51baf75031dd6d125b598e)
Change-Id: I06f01aa8fe5fdc06b2d36cfb9c68feb244c2e5de
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 25806fa..f65a50f 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -904,7 +904,8 @@
if (pool.isEmpty()) {
return true;
}
- Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool);
+ Entry moved =
+ addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool);
deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
if (!moved.isEmpty()) {
@@ -919,9 +920,9 @@
* Initializes the data used by the migrateTun() method.
*
* This is the first pass iteration which does the following work:
- * (1) Adds up all the traffic through tun0.
- * (2) Adds up all the traffic through the tunUid's underlyingIface
+ * (1) Adds up all the traffic through the tunUid's underlyingIface
* (both foreground and background).
+ * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
*/
private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
@@ -941,8 +942,9 @@
underlyingIfaceTotal.add(recycle);
}
- if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) {
- // Add up all tunIface traffic.
+ if (recycle.uid != tunUid && recycle.tag == TAG_NONE
+ && Objects.equals(tunIface, recycle.iface)) {
+ // Add up all tunIface traffic excluding traffic from the vpn app itself.
tunIfaceTotal.add(recycle);
}
}
@@ -958,13 +960,15 @@
return pool;
}
- private Entry addTrafficToApplications(String tunIface, String underlyingIface,
+ private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface,
Entry tunIfaceTotal, Entry pool) {
Entry moved = new Entry();
Entry tmpEntry = new Entry();
tmpEntry.iface = underlyingIface;
for (int i = 0; i < size; i++) {
- if (Objects.equals(iface[i], tunIface)) {
+ // the vpn app is excluded from the redistribution but all moved traffic will be
+ // deducted from the vpn app (see deductTrafficFromVpnApp below).
+ if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) {
if (tunIfaceTotal.rxBytes > 0) {
tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
} else {