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

Commit 1ea4cc64 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Return stats from inactive ifaces, packet counts."

parents eb982f39 fd8be3e5
Loading
Loading
Loading
Loading
+110 −25
Original line number Diff line number Diff line
@@ -43,17 +43,41 @@ public class NetworkStats implements Parcelable {
    /** {@link #tag} value for without tag. */
    public static final int TAG_NONE = 0;

    // TODO: move public fields to Entry accessors, then undeprecate
    // TODO: refactor rx/tx to rxBytes/txBytes

    /**
     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
     * generated.
     */
    @Deprecated
    public final long elapsedRealtime;
    @Deprecated
    public int size;
    @Deprecated
    public String[] iface;
    @Deprecated
    public int[] uid;
    @Deprecated
    public int[] tag;
    @Deprecated
    public long[] rx;
    @Deprecated
    public long[] rxPackets;
    @Deprecated
    public long[] tx;
    @Deprecated
    public long[] txPackets;

    public static class Entry {
        public String iface;
        public int uid;
        public int tag;
        public long rxBytes;
        public long rxPackets;
        public long txBytes;
        public long txPackets;
    }

    public NetworkStats(long elapsedRealtime, int initialSize) {
        this.elapsedRealtime = elapsedRealtime;
@@ -62,7 +86,9 @@ public class NetworkStats implements Parcelable {
        this.uid = new int[initialSize];
        this.tag = new int[initialSize];
        this.rx = new long[initialSize];
        this.rxPackets = new long[initialSize];
        this.tx = new long[initialSize];
        this.txPackets = new long[initialSize];
    }

    public NetworkStats(Parcel parcel) {
@@ -72,38 +98,82 @@ public class NetworkStats implements Parcelable {
        uid = parcel.createIntArray();
        tag = parcel.createIntArray();
        rx = parcel.createLongArray();
        rxPackets = parcel.createLongArray();
        tx = parcel.createLongArray();
        txPackets = parcel.createLongArray();
    }

    /**
     * Add new stats entry with given values.
     */
    public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) {
        final Entry entry = new Entry();
        entry.iface = iface;
        entry.uid = uid;
        entry.tag = tag;
        entry.rxBytes = rx;
        entry.txBytes = tx;
        return addValues(entry);
    }

    /**
     * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
     * object can be recycled across multiple calls.
     */
    public NetworkStats addValues(Entry entry) {
        if (size >= this.iface.length) {
            final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
            this.iface = Arrays.copyOf(this.iface, newLength);
            this.uid = Arrays.copyOf(this.uid, newLength);
            this.tag = Arrays.copyOf(this.tag, newLength);
            this.rx = Arrays.copyOf(this.rx, newLength);
            this.tx = Arrays.copyOf(this.tx, newLength);
        }

        this.iface[size] = iface;
        this.uid[size] = uid;
        this.tag[size] = tag;
        this.rx[size] = rx;
        this.tx[size] = tx;
            final int newLength = Math.max(iface.length, 10) * 3 / 2;
            iface = Arrays.copyOf(iface, newLength);
            uid = Arrays.copyOf(uid, newLength);
            tag = Arrays.copyOf(tag, newLength);
            rx = Arrays.copyOf(rx, newLength);
            rxPackets = Arrays.copyOf(rxPackets, newLength);
            tx = Arrays.copyOf(tx, newLength);
            txPackets = Arrays.copyOf(txPackets, newLength);
        }

        iface[size] = entry.iface;
        uid[size] = entry.uid;
        tag[size] = entry.tag;
        rx[size] = entry.rxBytes;
        rxPackets[size] = entry.rxPackets;
        tx[size] = entry.txBytes;
        txPackets[size] = entry.txPackets;
        size++;

        return this;
    }

    /**
     * Return specific stats entry.
     */
    public Entry getValues(int i, Entry recycle) {
        final Entry entry = recycle != null ? recycle : new Entry();
        entry.iface = iface[i];
        entry.uid = uid[i];
        entry.tag = tag[i];
        entry.rxBytes = rx[i];
        entry.rxPackets = rxPackets[i];
        entry.txBytes = tx[i];
        entry.txPackets = txPackets[i];
        return entry;
    }

    public long getElapsedRealtime() {
        return elapsedRealtime;
    }

    public int size() {
        return size;
    }

    /**
     * Combine given values with an existing row, or create a new row if
     * {@link #findIndex(String, int, int)} is unable to find match. Can also be
     * used to subtract values from existing rows.
     */
    public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) {
        // TODO: extent to accept rxPackets/txPackets
        final int i = findIndex(iface, uid, tag);
        if (i == -1) {
            // only create new entry when positive contribution
@@ -199,30 +269,41 @@ public class NetworkStats implements Parcelable {
        }

        // result will have our rows, and elapsed time between snapshots
        final Entry entry = new Entry();
        final NetworkStats result = new NetworkStats(deltaRealtime, size);
        for (int i = 0; i < size; i++) {
            final String iface = this.iface[i];
            final int uid = this.uid[i];
            final int tag = this.tag[i];
            entry.iface = iface[i];
            entry.uid = uid[i];
            entry.tag = tag[i];

            // find remote row that matches, and subtract
            final int j = value.findIndex(iface, uid, tag);
            final int j = value.findIndex(entry.iface, entry.uid, entry.tag);
            if (j == -1) {
                // newly appearing row, return entire value
                result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]);
                entry.rxBytes = rx[i];
                entry.rxPackets = rxPackets[i];
                entry.txBytes = tx[i];
                entry.txPackets = txPackets[i];
            } else {
                // existing row, subtract remote value
                long rx = this.rx[i] - value.rx[j];
                long tx = this.tx[i] - value.tx[j];
                if (enforceMonotonic && (rx < 0 || tx < 0)) {
                entry.rxBytes = rx[i] - value.rx[j];
                entry.rxPackets = rxPackets[i] - value.rxPackets[j];
                entry.txBytes = tx[i] - value.tx[j];
                entry.txPackets = txPackets[i] - value.txPackets[j];
                if (enforceMonotonic
                        && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
                                || entry.txPackets < 0)) {
                    throw new IllegalArgumentException("found non-monotonic values");
                }
                if (clampNegative) {
                    rx = Math.max(0, rx);
                    tx = Math.max(0, tx);
                    entry.rxBytes = Math.max(0, entry.rxBytes);
                    entry.rxPackets = Math.max(0, entry.rxPackets);
                    entry.txBytes = Math.max(0, entry.txBytes);
                    entry.txPackets = Math.max(0, entry.txPackets);
                }
                result.addEntry(iface, uid, tag, rx, tx);
            }

            result.addValues(entry);
        }

        return result;
@@ -235,13 +316,15 @@ public class NetworkStats implements Parcelable {
    public void dump(String prefix, PrintWriter pw) {
        pw.print(prefix);
        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
        for (int i = 0; i < iface.length; i++) {
        for (int i = 0; i < size; i++) {
            pw.print(prefix);
            pw.print("  iface="); pw.print(iface[i]);
            pw.print(" uid="); pw.print(uid[i]);
            pw.print(" tag="); pw.print(tag[i]);
            pw.print(" rx="); pw.print(rx[i]);
            pw.print(" tx="); pw.println(tx[i]);
            pw.print(" rxBytes="); pw.print(rx[i]);
            pw.print(" rxPackets="); pw.print(rxPackets[i]);
            pw.print(" txBytes="); pw.print(tx[i]);
            pw.print(" txPackets="); pw.println(txPackets[i]);
        }
    }

@@ -265,7 +348,9 @@ public class NetworkStats implements Parcelable {
        dest.writeIntArray(uid);
        dest.writeIntArray(tag);
        dest.writeLongArray(rx);
        dest.writeLongArray(rxPackets);
        dest.writeLongArray(tx);
        dest.writeLongArray(txPackets);
    }

    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+3 −3
Original line number Diff line number Diff line
@@ -44,20 +44,20 @@ public class NetworkStatsTest extends TestCase {
    public void testAddEntryGrow() throws Exception {
        final NetworkStats stats = new NetworkStats(TEST_START, 2);

        assertEquals(0, stats.size);
        assertEquals(0, stats.size());
        assertEquals(2, stats.iface.length);

        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 1L, 2L);
        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L);

        assertEquals(2, stats.size);
        assertEquals(2, stats.size());
        assertEquals(2, stats.iface.length);

        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 3L, 4L);
        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 4L, 4L);
        stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 5L, 5L);

        assertEquals(5, stats.size);
        assertEquals(5, stats.size());
        assertTrue(stats.iface.length >= 5);

        assertEquals(1L, stats.rx[0]);
+111 −27
Original line number Diff line number Diff line
@@ -77,11 +77,15 @@ class NetworkManagementService extends INetworkManagementService.Stub {

    /** Path to {@code /proc/uid_stat}. */
    @Deprecated
    private final File mProcStatsUidstat;
    private final File mStatsUid;
    /** Path to {@code /proc/net/dev}. */
    private final File mStatsIface;
    /** Path to {@code /proc/net/xt_qtaguid/stats}. */
    private final File mProcStatsNetfilter;
    private final File mStatsXtUid;
    /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
    private final File mStatsXtIface;

    /** {@link #mProcStatsNetfilter} headers. */
    /** {@link #mStatsXtUid} headers. */
    private static final String KEY_IFACE = "iface";
    private static final String KEY_TAG_HEX = "acct_tag_hex";
    private static final String KEY_UID = "uid_tag_int";
@@ -137,8 +141,10 @@ class NetworkManagementService extends INetworkManagementService.Stub {
        mContext = context;
        mObservers = new ArrayList<INetworkManagementEventObserver>();

        mProcStatsUidstat = new File(procRoot, "uid_stat");
        mProcStatsNetfilter = new File(procRoot, "net/xt_qtaguid/stats");
        mStatsUid = new File(procRoot, "uid_stat");
        mStatsIface = new File(procRoot, "net/dev");
        mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
        mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");

        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
            return;
@@ -161,9 +167,12 @@ class NetworkManagementService extends INetworkManagementService.Stub {
    }

    // @VisibleForTesting
    public static NetworkManagementService createForTest(Context context, File procRoot) {
    public static NetworkManagementService createForTest(
            Context context, File procRoot, boolean bandwidthControlEnabled) {
        // TODO: eventually connect with mock netd
        return new NetworkManagementService(context, procRoot);
        final NetworkManagementService service = new NetworkManagementService(context, procRoot);
        service.mBandwidthControlEnabled = bandwidthControlEnabled;
        return service;
    }

    public void systemReady() {
@@ -930,13 +939,68 @@ class NetworkManagementService extends INetworkManagementService.Stub {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");

        final String[] ifaces = listInterfaces();
        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
        final NetworkStats.Entry entry = new NetworkStats.Entry();

        final HashSet<String> activeIfaces = Sets.newHashSet();
        final ArrayList<String> values = Lists.newArrayList();

        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(mStatsIface));

            // skip first two header lines
            reader.readLine();
            reader.readLine();

            // parse remaining lines
            String line;
            while ((line = reader.readLine()) != null) {
                splitLine(line, values);

                try {
                    entry.iface = values.get(0);
                    entry.uid = UID_ALL;
                    entry.tag = TAG_NONE;
                    entry.rxBytes = Long.parseLong(values.get(1));
                    entry.rxPackets = Long.parseLong(values.get(2));
                    entry.txBytes = Long.parseLong(values.get(9));
                    entry.txPackets = Long.parseLong(values.get(10));

                    activeIfaces.add(entry.iface);
                    stats.addValues(entry);
                } catch (NumberFormatException e) {
                    Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
                }
            }
        } catch (IOException e) {
            Slog.w(TAG, "problem parsing stats: " + e);
        } finally {
            IoUtils.closeQuietly(reader);
        }

        if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);

        // splice in stats from any disabled ifaces
        if (mBandwidthControlEnabled) {
            final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
            xtIfaces.removeAll(activeIfaces);

            for (String iface : xtIfaces) {
                final File ifacePath = new File(mStatsXtIface, iface);

                entry.iface = iface;
                entry.uid = UID_ALL;
                entry.tag = TAG_NONE;
                entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
                entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
                entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
                entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));

        for (String iface : ifaces) {
            final long rx = getInterfaceCounter(iface, true);
            final long tx = getInterfaceCounter(iface, false);
            stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
                stats.addValues(entry);
            }

            if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
        }

        return stats;
@@ -1063,13 +1127,15 @@ class NetworkManagementService extends INetworkManagementService.Stub {
     */
    private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
        final NetworkStats.Entry entry = new NetworkStats.Entry();

        final ArrayList<String> keys = Lists.newArrayList();
        final ArrayList<String> values = Lists.newArrayList();
        final HashMap<String, String> parsed = Maps.newHashMap();

        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(mProcStatsNetfilter));
            reader = new BufferedReader(new FileReader(mStatsXtUid));

            // parse first line as header
            String line = reader.readLine();
@@ -1081,15 +1147,16 @@ class NetworkManagementService extends INetworkManagementService.Stub {
                parseLine(keys, values, parsed);

                try {
                    final String iface = parsed.get(KEY_IFACE);
                    final int tag = NetworkManagementSocketTagger.kernelToTag(
                    // TODO: add rxPackets/txPackets once kernel exports
                    entry.iface = parsed.get(KEY_IFACE);
                    entry.tag = NetworkManagementSocketTagger.kernelToTag(
                            parsed.get(KEY_TAG_HEX));
                    final int uid = Integer.parseInt(parsed.get(KEY_UID));
                    final long rx = Long.parseLong(parsed.get(KEY_RX));
                    final long tx = Long.parseLong(parsed.get(KEY_TX));
                    entry.uid = Integer.parseInt(parsed.get(KEY_UID));
                    entry.rxBytes = Long.parseLong(parsed.get(KEY_RX));
                    entry.txBytes = Long.parseLong(parsed.get(KEY_TX));

                    if (limitUid == UID_ALL || limitUid == uid) {
                        stats.addEntry(iface, uid, tag, rx, tx);
                    if (limitUid == UID_ALL || limitUid == entry.uid) {
                        stats.addValues(entry);
                    }
                } catch (NumberFormatException e) {
                    Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
@@ -1114,19 +1181,27 @@ class NetworkManagementService extends INetworkManagementService.Stub {
    private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
        final String[] knownUids;
        if (limitUid == UID_ALL) {
            knownUids = mProcStatsUidstat.list();
            knownUids = fileListWithoutNull(mStatsUid);
        } else {
            knownUids = new String[] { String.valueOf(limitUid) };
        }

        final NetworkStats stats = new NetworkStats(
                SystemClock.elapsedRealtime(), knownUids.length);
        final NetworkStats.Entry entry = new NetworkStats.Entry();
        for (String uid : knownUids) {
            final int uidInt = Integer.parseInt(uid);
            final File uidPath = new File(mProcStatsUidstat, uid);
            final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
            final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
            stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
            final File uidPath = new File(mStatsUid, uid);

            entry.iface = IFACE_ALL;
            entry.uid = uidInt;
            entry.tag = TAG_NONE;
            entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
            entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
            entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
            entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));

            stats.addValues(entry);
        }

        return stats;
@@ -1197,7 +1272,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
    private static void splitLine(String line, ArrayList<String> outSplit) {
        outSplit.clear();

        final StringTokenizer t = new StringTokenizer(line);
        final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
        while (t.hasMoreTokens()) {
            outSplit.add(t.nextToken());
        }
@@ -1232,6 +1307,15 @@ class NetworkManagementService extends INetworkManagementService.Stub {
        }
    }

    /**
     * Wrapper for {@link File#list()} that returns empty array instead of
     * {@code null}.
     */
    private static String[] fileListWithoutNull(File file) {
        final String[] list = file.list();
        return list != null ? list : new String[0];
    }

    public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+8 −0
Original line number Diff line number Diff line
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:    8308     116    0    0    0     0          0         0     8308     116    0    0    0     0       0          0
rmnet0: 1507570    2205    0    0    0     0          0         0   489339    2237    0    0    0     0       0          0
  ifb0:   52454     151    0  151    0     0          0         0        0       0    0    0    0     0       0          0
  ifb1:   52454     151    0  151    0     0          0         0        0       0    0    0    0     0       0          0
  sit0:       0       0    0    0    0     0          0         0        0       0  148    0    0     0       0          0
ip6tnl0:       0       0    0    0    0     0          0         0        0       0  151  151    0     0       0          0
+58 −8
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server;

import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import static com.android.server.NetworkManagementSocketTagger.tagToKernel;

@@ -25,9 +27,11 @@ import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;

import com.android.frameworks.servicestests.R;
import com.google.common.io.Files;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStream;

@@ -46,14 +50,23 @@ public class NetworkManagementServiceTest extends AndroidTestCase {
    public void setUp() throws Exception {
        super.setUp();

        mTestProc = getContext().getFilesDir();
        mService = NetworkManagementService.createForTest(mContext, mTestProc);
        final File canonicalFilesDir = getContext().getFilesDir().getCanonicalFile();
        mTestProc = new File(canonicalFilesDir, "proc");
        if (mTestProc.exists()) {
            Files.deleteRecursively(mTestProc);
        }

        mService = NetworkManagementService.createForTest(mContext, mTestProc, true);
    }

    @Override
    public void tearDown() throws Exception {
        mService = null;

        if (mTestProc.exists()) {
            Files.deleteRecursively(mTestProc);
        }

        super.tearDown();
    }

@@ -61,7 +74,7 @@ public class NetworkManagementServiceTest extends AndroidTestCase {
        stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats"));

        final NetworkStats stats = mService.getNetworkStatsDetail();
        assertEquals(31, stats.size);
        assertEquals(31, stats.size());
        assertStatsEntry(stats, "wlan0", 0, 0, 14615L, 4270L);
        assertStatsEntry(stats, "wlan0", 10004, 0, 333821L, 53558L);
        assertStatsEntry(stats, "wlan0", 10004, 1947740890, 18725L, 1066L);
@@ -73,11 +86,37 @@ public class NetworkManagementServiceTest extends AndroidTestCase {
        stageFile(R.raw.xt_qtaguid_extended, new File(mTestProc, "net/xt_qtaguid/stats"));

        final NetworkStats stats = mService.getNetworkStatsDetail();
        assertEquals(2, stats.size);
        assertEquals(2, stats.size());
        assertStatsEntry(stats, "test0", 1000, 0, 1024L, 2048L);
        assertStatsEntry(stats, "test0", 1000, 0xF00D, 512L, 512L);
    }

    public void testNetworkStatsSummary() throws Exception {
        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));

        final NetworkStats stats = mService.getNetworkStatsSummary();
        assertEquals(6, stats.size());
        assertStatsEntry(stats, "lo", UID_ALL, TAG_NONE, 8308L, 8308L);
        assertStatsEntry(stats, "rmnet0", UID_ALL, TAG_NONE, 1507570L, 489339L);
        assertStatsEntry(stats, "ifb0", UID_ALL, TAG_NONE, 52454L, 0L);
        assertStatsEntry(stats, "ifb1", UID_ALL, TAG_NONE, 52454L, 0L);
        assertStatsEntry(stats, "sit0", UID_ALL, TAG_NONE, 0L, 0L);
        assertStatsEntry(stats, "ip6tnl0", UID_ALL, TAG_NONE, 0L, 0L);
    }

    public void testNetworkStatsSummaryDown() throws Exception {
        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
        stageLong(1024L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_bytes"));
        stageLong(128L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_packets"));
        stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
        stageLong(256L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_packets"));

        final NetworkStats stats = mService.getNetworkStatsSummary();
        assertEquals(7, stats.size());
        assertStatsEntry(stats, "rmnet0", UID_ALL, TAG_NONE, 1507570L, 489339L);
        assertStatsEntry(stats, "wlan0", UID_ALL, TAG_NONE, 1024L, 2048L);
    }

    public void testKernelTags() throws Exception {
        assertEquals("0", tagToKernel(0x0));
        assertEquals("214748364800", tagToKernel(0x32));
@@ -90,7 +129,6 @@ public class NetworkManagementServiceTest extends AndroidTestCase {
        assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
        assertEquals(0, kernelToTag("0x0000000000000000"));
        assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000"));

    }

    /**
@@ -111,11 +149,23 @@ public class NetworkManagementServiceTest extends AndroidTestCase {
        }
    }

    private void stageLong(long value, File file) throws Exception {
        new File(file.getParent()).mkdirs();
        FileWriter out = null;
        try {
            out = new FileWriter(file);
            out.write(Long.toString(value));
        } finally {
            IoUtils.closeQuietly(out);
        }
    }

    private static void assertStatsEntry(
            NetworkStats stats, String iface, int uid, int tag, long rx, long tx) {
            NetworkStats stats, String iface, int uid, int tag, long rxBytes, long txBytes) {
        final int i = stats.findIndex(iface, uid, tag);
        assertEquals(rx, stats.rx[i]);
        assertEquals(tx, stats.tx[i]);
        final NetworkStats.Entry entry = stats.getValues(i, null);
        assertEquals(rxBytes, entry.rxBytes);
        assertEquals(txBytes, entry.txBytes);
    }

}