From 3657ce96902a1d0935bad433376fdab491018c17 Mon Sep 17 00:00:00 2001 From: Mike SU Date: Mon, 26 Nov 2018 15:05:13 +0800 Subject: [PATCH] fix getIfaceStats and getTotalStats bug root cause: getIfaceStats and getTotalStats is directly reading iface_stat_fmt or eBPF, not include tether stats. solution: add tether stats to getIfaceStats and getTotalStats. Bug: 120039819 Test case1: 1. tether offload is enabled on phone, enable MHS on phone. 2. Use test app to check getMobileRxBytes->getIfaceStats 3. Download 10M file on MHS client 4. Use test app to check getMobileRxBytes->getIfaceStats again result: getMobileRxBytes increased around 10M Test case2: 1. tether offload is disabled on phone, enable MHS on phone. repeat above step 2~4 result: getMobileRxBytes increased around 10M Following CTS cases passed run cts -m CtsNetTestCases --test android.net.cts.TrafficStatsTest run cts -m CtsUsageStatsTestCases --test android.app.usage.cts.NetworkUsageStatsTest Change-Id: I3d94acb71c142ec38b750e58822881ff383341cc --- .../server/net/NetworkStatsService.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b0adf954ca..2e7cbc684c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -955,12 +955,64 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getIfaceStats(String iface, int type) { - return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + if (nativeIfaceStats == -1) { + return nativeIfaceStats; + } else { + // When tethering offload is in use, nativeIfaceStats does not contain usage from + // offload, add it back here. + // When tethering offload is not in use, nativeIfaceStats contains tethering usage. + // this does not cause double-counting of tethering traffic, because + // NetdTetheringStatsProvider returns zero NetworkStats + // when called with STATS_PER_IFACE. + return nativeIfaceStats + getTetherStats(iface, type); + } } @Override public long getTotalStats(int type) { - return nativeGetTotalStat(type, checkBpfStatsEnable()); + long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable()); + if (nativeTotalStats == -1) { + return nativeTotalStats; + } else { + // Refer to comment in getIfaceStats + return nativeTotalStats + getTetherStats(IFACE_ALL, type); + } + } + + private long getTetherStats(String iface, int type) { + final NetworkStats tetherSnapshot; + final long token = Binder.clearCallingIdentity(); + try { + tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); + } catch (RemoteException e) { + Slog.w(TAG, "Error get TetherStats: " + e); + return 0; + } finally { + Binder.restoreCallingIdentity(token); + } + HashSet limitIfaces; + if (iface == IFACE_ALL) { + limitIfaces = null; + } else { + limitIfaces = new HashSet(); + limitIfaces.add(iface); + } + NetworkStats.Entry entry = tetherSnapshot.getTotal(null, limitIfaces); + if (LOGD) Slog.d(TAG, "TetherStats: iface=" + iface + " type=" + type + + " entry=" + entry); + switch (type) { + case 0: // TYPE_RX_BYTES + return entry.rxBytes; + case 1: // TYPE_RX_PACKETS + return entry.rxPackets; + case 2: // TYPE_TX_BYTES + return entry.txBytes; + case 3: // TYPE_TX_PACKETS + return entry.txPackets; + default: + return 0; + } } private boolean checkBpfStatsEnable() {