Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce75675a authored by Mike SU's avatar Mike SU Committed by Zhang Wei-e7976c
Browse files

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
parent c0f3daa1
Loading
Loading
Loading
Loading
+54 −2
Original line number Diff line number Diff line
@@ -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<String> limitIfaces;
        if (iface == IFACE_ALL) {
            limitIfaces = null;
        } else {
            limitIfaces = new HashSet<String>();
            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() {