FileDocCategorySizeDatePackage
NetworkStatsFactory.javaAPI DocAndroid 5.1 API13619Thu Mar 12 22:22:10 GMT 2015com.android.internal.net

NetworkStatsFactory

public class NetworkStatsFactory extends Object
Creates {@link NetworkStats} instances by parsing various {@code /proc/} files as needed.

Fields Summary
private static final String
TAG
private static final boolean
USE_NATIVE_PARSING
private static final boolean
SANITY_CHECK_NATIVE
private final File
mStatsXtIfaceAll
Path to {@code /proc/net/xt_qtaguid/iface_stat_all}.
private final File
mStatsXtIfaceFmt
Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}.
private final File
mStatsXtUid
Path to {@code /proc/net/xt_qtaguid/stats}.
private static final android.util.ArrayMap
sStackedIfaces
Constructors Summary
public NetworkStatsFactory()

        this(new File("/proc/"));
    
public NetworkStatsFactory(File procRoot)

        mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
        mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt");
        mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
    
Methods Summary
public voidassertEquals(android.net.NetworkStats expected, android.net.NetworkStats actual)

        if (expected.size() != actual.size()) {
            throw new AssertionError(
                    "Expected size " + expected.size() + ", actual size " + actual.size());
        }

        NetworkStats.Entry expectedRow = null;
        NetworkStats.Entry actualRow = null;
        for (int i = 0; i < expected.size(); i++) {
            expectedRow = expected.getValues(i, expectedRow);
            actualRow = actual.getValues(i, actualRow);
            if (!expectedRow.equals(actualRow)) {
                throw new AssertionError(
                        "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow);
            }
        }
    
public static android.net.NetworkStatsjavaReadNetworkStatsDetail(java.io.File detailPath, int limitUid, java.lang.String[] limitIfaces, int limitTag)
Parse and return {@link NetworkStats} with UID-level details. Values are expected to monotonically increase since device boot.

        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();

        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
        final NetworkStats.Entry entry = new NetworkStats.Entry();

        int idx = 1;
        int lastIdx = 1;

        ProcFileReader reader = null;
        try {
            // open and consume header line
            reader = new ProcFileReader(new FileInputStream(detailPath));
            reader.finishLine();

            while (reader.hasMoreData()) {
                idx = reader.nextInt();
                if (idx != lastIdx + 1) {
                    throw new ProtocolException(
                            "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
                }
                lastIdx = idx;

                entry.iface = reader.nextString();
                entry.tag = kernelToTag(reader.nextString());
                entry.uid = reader.nextInt();
                entry.set = reader.nextInt();
                entry.rxBytes = reader.nextLong();
                entry.rxPackets = reader.nextLong();
                entry.txBytes = reader.nextLong();
                entry.txPackets = reader.nextLong();

                if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
                        && (limitUid == UID_ALL || limitUid == entry.uid)
                        && (limitTag == TAG_ALL || limitTag == entry.tag)) {
                    stats.addValues(entry);
                }

                reader.finishLine();
            }
        } catch (NullPointerException e) {
            throw new ProtocolException("problem parsing idx " + idx, e);
        } catch (NumberFormatException e) {
            throw new ProtocolException("problem parsing idx " + idx, e);
        } finally {
            IoUtils.closeQuietly(reader);
            StrictMode.setThreadPolicy(savedPolicy);
        }

        return stats;
    
public static native intnativeReadNetworkStatsDetail(android.net.NetworkStats stats, java.lang.String path, int limitUid, java.lang.String[] limitIfaces, int limitTag)
Parse statistics from file into given {@link NetworkStats} object. Values are expected to monotonically increase since device boot.

public static voidnoteStackedIface(java.lang.String stackedIface, java.lang.String baseIface)


           
        synchronized (sStackedIfaces) {
            if (baseIface != null) {
                sStackedIfaces.put(stackedIface, baseIface);
            } else {
                sStackedIfaces.remove(stackedIface);
            }
        }
    
public android.net.NetworkStatsreadNetworkStatsDetail()

        return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
    
public android.net.NetworkStatsreadNetworkStatsDetail(int limitUid, java.lang.String[] limitIfaces, int limitTag, android.net.NetworkStats lastStats)

        final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag,
                lastStats);

        synchronized (sStackedIfaces) {
            // Sigh, xt_qtaguid ends up double-counting tx traffic going through
            // clatd interfaces, so we need to subtract it here.
            final int size = sStackedIfaces.size();
            for (int i = 0; i < size; i++) {
                final String stackedIface = sStackedIfaces.keyAt(i);
                final String baseIface = sStackedIfaces.valueAt(i);

                // Count up the tx traffic and subtract from root UID on the
                // base interface.
                NetworkStats.Entry adjust = new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L,
                        0L, 0L);
                NetworkStats.Entry entry = null;
                for (int j = 0; j < stats.size(); j++) {
                    entry = stats.getValues(j, entry);
                    if (Objects.equals(entry.iface, stackedIface)) {
                        adjust.txBytes -= entry.txBytes;
                        adjust.txPackets -= entry.txPackets;
                    }
                }
                stats.combineValues(adjust);
            }
        }

        // Double sigh, all rx traffic on clat needs to be tweaked to
        // account for the dropped IPv6 header size post-unwrap.
        NetworkStats.Entry entry = null;
        for (int i = 0; i < stats.size(); i++) {
            entry = stats.getValues(i, entry);
            if (entry.iface != null && entry.iface.startsWith("clat")) {
                // Delta between IPv4 header (20b) and IPv6 header (40b)
                entry.rxBytes = entry.rxPackets * 20;
                entry.rxPackets = 0;
                entry.txBytes = 0;
                entry.txPackets = 0;
                stats.combineValues(entry);
            }
        }

        return stats;
    
private android.net.NetworkStatsreadNetworkStatsDetailInternal(int limitUid, java.lang.String[] limitIfaces, int limitTag, android.net.NetworkStats lastStats)

        if (USE_NATIVE_PARSING) {
            final NetworkStats stats;
            if (lastStats != null) {
                stats = lastStats;
                stats.setElapsedRealtime(SystemClock.elapsedRealtime());
            } else {
                stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
            }
            if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
                    limitIfaces, limitTag) != 0) {
                throw new IOException("Failed to parse network stats");
            }
            if (SANITY_CHECK_NATIVE) {
                final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
                        limitIfaces, limitTag);
                assertEquals(javaStats, stats);
            }
            return stats;
        } else {
            return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag);
        }
    
public android.net.NetworkStatsreadNetworkStatsSummaryDev()
Parse and return interface-level summary {@link NetworkStats} measured using {@code /proc/net/dev} style hooks, which may include non IP layer traffic. Values monotonically increase since device boot, and may include details about inactive interfaces.

throws
IllegalStateException when problem parsing stats.

        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();

        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
        final NetworkStats.Entry entry = new NetworkStats.Entry();

        ProcFileReader reader = null;
        try {
            reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceAll));

            while (reader.hasMoreData()) {
                entry.iface = reader.nextString();
                entry.uid = UID_ALL;
                entry.set = SET_ALL;
                entry.tag = TAG_NONE;

                final boolean active = reader.nextInt() != 0;

                // always include snapshot values
                entry.rxBytes = reader.nextLong();
                entry.rxPackets = reader.nextLong();
                entry.txBytes = reader.nextLong();
                entry.txPackets = reader.nextLong();

                // fold in active numbers, but only when active
                if (active) {
                    entry.rxBytes += reader.nextLong();
                    entry.rxPackets += reader.nextLong();
                    entry.txBytes += reader.nextLong();
                    entry.txPackets += reader.nextLong();
                }

                stats.addValues(entry);
                reader.finishLine();
            }
        } catch (NullPointerException e) {
            throw new ProtocolException("problem parsing stats", e);
        } catch (NumberFormatException e) {
            throw new ProtocolException("problem parsing stats", e);
        } finally {
            IoUtils.closeQuietly(reader);
            StrictMode.setThreadPolicy(savedPolicy);
        }
        return stats;
    
public android.net.NetworkStatsreadNetworkStatsSummaryXt()
Parse and return interface-level summary {@link NetworkStats}. Designed to return only IP layer traffic. Values monotonically increase since device boot, and may include details about inactive interfaces.

throws
IllegalStateException when problem parsing stats.

        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();

        // return null when kernel doesn't support
        if (!mStatsXtIfaceFmt.exists()) return null;

        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
        final NetworkStats.Entry entry = new NetworkStats.Entry();

        ProcFileReader reader = null;
        try {
            // open and consume header line
            reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt));
            reader.finishLine();

            while (reader.hasMoreData()) {
                entry.iface = reader.nextString();
                entry.uid = UID_ALL;
                entry.set = SET_ALL;
                entry.tag = TAG_NONE;

                entry.rxBytes = reader.nextLong();
                entry.rxPackets = reader.nextLong();
                entry.txBytes = reader.nextLong();
                entry.txPackets = reader.nextLong();

                stats.addValues(entry);
                reader.finishLine();
            }
        } catch (NullPointerException e) {
            throw new ProtocolException("problem parsing stats", e);
        } catch (NumberFormatException e) {
            throw new ProtocolException("problem parsing stats", e);
        } finally {
            IoUtils.closeQuietly(reader);
            StrictMode.setThreadPolicy(savedPolicy);
        }
        return stats;