19a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey/*
29a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * Copyright (C) 2011 The Android Open Source Project
39a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey *
49a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
59a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * you may not use this file except in compliance with the License.
69a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * You may obtain a copy of the License at
79a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey *
89a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
99a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey *
109a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
119a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
129a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * See the License for the specific language governing permissions and
149a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * limitations under the License.
159a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey */
169a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
179a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeypackage android.net;
189a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
19163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkeyimport static com.android.internal.util.Preconditions.checkNotNull;
20163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
219a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.Parcel;
229a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.Parcelable;
239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.SystemClock;
2461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport android.util.SparseBooleanArray;
259a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
26a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport com.android.internal.util.Objects;
27a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
289a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.CharArrayWriter;
299a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.PrintWriter;
304a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkeyimport java.util.Arrays;
3175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.HashSet;
329a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
339a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey/**
3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of active network statistics. Can contain summary details across
3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * all interfaces, or details with per-UID granularity. Internally stores data
3675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * as a large table, closely matching {@code /proc/} data format. This structure
3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * optimizes for rapid in-memory comparison, but consider using
3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link NetworkStatsHistory} when persisting.
399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey *
409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * @hide
419a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey */
429a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeypublic class NetworkStats implements Parcelable {
4347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey    private static final String TAG = "NetworkStats";
4447eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #iface} value when interface details unavailable. */
469a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final String IFACE_ALL = null;
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #uid} value when UID details unavailable. */
4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final int UID_ALL = -1;
49b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value when all sets combined. */
50b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_ALL = -1;
51b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where background data is accounted. */
52b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_DEFAULT = 0;
53b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where foreground data is accounted. */
54b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_FOREGROUND = 1;
55b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #tag} value for total data across all tags. */
561b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    public static final int TAG_NONE = 0;
57eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
58163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    // TODO: move fields to "mVariable" notation
59163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
609a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
619a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
629a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * generated.
639a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
64d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private final long elapsedRealtime;
65d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int size;
66d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private String[] iface;
67d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int[] uid;
68b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    private int[] set;
69d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int[] tag;
70d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
71d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxPackets;
72d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
73d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txPackets;
7463d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
75fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
76fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public static class Entry {
77fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public String iface;
78fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public int uid;
79b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        public int set;
80fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public int tag;
81fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long rxBytes;
82fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long rxPackets;
83fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long txBytes;
84fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long txPackets;
8563d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
86d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
87d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public Entry() {
88b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
8963d27a9233fed934340231f438493746084a681dJeff Sharkey        }
9063d27a9233fed934340231f438493746084a681dJeff Sharkey
9163d27a9233fed934340231f438493746084a681dJeff Sharkey        public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
92b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
93b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                    operations);
94d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        }
95d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
96b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
97b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                long txBytes, long txPackets, long operations) {
98d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.iface = iface;
99d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.uid = uid;
100b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this.set = set;
101d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.tag = tag;
102d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.rxBytes = rxBytes;
103d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.rxPackets = rxPackets;
104d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.txBytes = txBytes;
105d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.txPackets = txPackets;
106a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            this.operations = operations;
107d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        }
108b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey
109b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        @Override
110b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        public String toString() {
111b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            final StringBuilder builder = new StringBuilder();
112b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append("iface=").append(iface);
113b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" uid=").append(uid);
114b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" set=").append(setToString(set));
115b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" tag=").append(tagToString(tag));
116b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxBytes=").append(rxBytes);
117b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxPackets=").append(rxPackets);
118b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txBytes=").append(txBytes);
119b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txPackets=").append(txPackets);
120b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" operations=").append(operations);
121b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            return builder.toString();
122b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        }
123fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
1249a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1254a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStats(long elapsedRealtime, int initialSize) {
1269a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        this.elapsedRealtime = elapsedRealtime;
1274a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.size = 0;
1284a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.iface = new String[initialSize];
1294a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.uid = new int[initialSize];
130b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        this.set = new int[initialSize];
1311b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        this.tag = new int[initialSize];
132d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.rxBytes = new long[initialSize];
133fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.rxPackets = new long[initialSize];
134d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.txBytes = new long[initialSize];
135fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.txPackets = new long[initialSize];
13663d27a9233fed934340231f438493746084a681dJeff Sharkey        this.operations = new long[initialSize];
1379a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1389a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public NetworkStats(Parcel parcel) {
1409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        elapsedRealtime = parcel.readLong();
1414a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size = parcel.readInt();
1429a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        iface = parcel.createStringArray();
1439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        uid = parcel.createIntArray();
144b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set = parcel.createIntArray();
1451b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        tag = parcel.createIntArray();
146d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes = parcel.createLongArray();
147fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets = parcel.createLongArray();
148d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes = parcel.createLongArray();
149fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets = parcel.createLongArray();
15063d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = parcel.createLongArray();
151a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
152a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
153a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /** {@inheritDoc} */
154a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void writeToParcel(Parcel dest, int flags) {
155a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLong(elapsedRealtime);
156a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeInt(size);
157a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeStringArray(iface);
158a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(uid);
159b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        dest.writeIntArray(set);
160a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(tag);
161a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxBytes);
162a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxPackets);
163a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txBytes);
164a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txPackets);
16563d27a9233fed934340231f438493746084a681dJeff Sharkey        dest.writeLongArray(operations);
1669a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1679a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1684abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    @Override
1694abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    public NetworkStats clone() {
1704abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
1714abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        NetworkStats.Entry entry = null;
1724abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        for (int i = 0; i < size; i++) {
1734abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey            entry = getValues(i, entry);
1744abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey            clone.addValues(entry);
1754abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        }
1764abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        return clone;
1774abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    }
1784abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey
179b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    // @VisibleForTesting
180b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addIfaceValues(
181b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
182b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(
183b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
184a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
185a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
186b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    // @VisibleForTesting
187b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
188b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
189b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(new Entry(
190b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
191fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
192fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
193fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
194fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
195fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * object can be recycled across multiple calls.
196fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
197fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public NetworkStats addValues(Entry entry) {
1984a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (size >= this.iface.length) {
199fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            final int newLength = Math.max(iface.length, 10) * 3 / 2;
200fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            iface = Arrays.copyOf(iface, newLength);
201fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            uid = Arrays.copyOf(uid, newLength);
202b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            set = Arrays.copyOf(set, newLength);
203fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            tag = Arrays.copyOf(tag, newLength);
204d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes = Arrays.copyOf(rxBytes, newLength);
205fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            rxPackets = Arrays.copyOf(rxPackets, newLength);
206d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes = Arrays.copyOf(txBytes, newLength);
207fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            txPackets = Arrays.copyOf(txPackets, newLength);
208a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations = Arrays.copyOf(operations, newLength);
2099a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
2109a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
211fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        iface[size] = entry.iface;
212fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        uid[size] = entry.uid;
213b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set[size] = entry.set;
214fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        tag[size] = entry.tag;
215d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes[size] = entry.rxBytes;
216fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets[size] = entry.rxPackets;
217d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes[size] = entry.txBytes;
218fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets[size] = entry.txPackets;
219a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        operations[size] = entry.operations;
2204a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size++;
2219a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2224a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return this;
2239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
2249a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2251b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    /**
226fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Return specific stats entry.
227fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
228fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public Entry getValues(int i, Entry recycle) {
229fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
230fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.iface = iface[i];
231fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.uid = uid[i];
232b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        entry.set = set[i];
233fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.tag = tag[i];
234d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.rxBytes = rxBytes[i];
235fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.rxPackets = rxPackets[i];
236d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.txBytes = txBytes[i];
237fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.txPackets = txPackets[i];
238a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        entry.operations = operations[i];
239fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return entry;
240fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
241fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
242fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public long getElapsedRealtime() {
243fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return elapsedRealtime;
244fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
245fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
2461059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
2471059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return age of this {@link NetworkStats} object with respect to
2481059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * {@link SystemClock#elapsedRealtime()}.
2491059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
2501059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public long getElapsedRealtimeAge() {
2511059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return SystemClock.elapsedRealtime() - elapsedRealtime;
2521059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
2531059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
254fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public int size() {
255fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return size;
256fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
257fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
258d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    // @VisibleForTesting
259d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int internalSize() {
260d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return iface.length;
261d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
262d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
263b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    @Deprecated
264d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
26563d27a9233fed934340231f438493746084a681dJeff Sharkey            long txBytes, long txPackets, long operations) {
266a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        return combineValues(
267b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
268b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
269b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
270b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
271b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
272b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return combineValues(new Entry(
273b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
274d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
275d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
276fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
2771b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     * Combine given values with an existing row, or create a new row if
278b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * {@link #findIndex(String, int, int, int)} is unable to find match. Can
279b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * also be used to subtract values from existing rows.
2801b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     */
281d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(Entry entry) {
282b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
2831b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        if (i == -1) {
2841b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            // only create new entry when positive contribution
285d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            addValues(entry);
2861b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        } else {
287d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes[i] += entry.rxBytes;
288d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxPackets[i] += entry.rxPackets;
289d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes[i] += entry.txBytes;
290d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txPackets[i] += entry.txPackets;
291a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations[i] += entry.operations;
2921b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
2931b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        return this;
294eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
295eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
2969a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
297905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Combine all values from another {@link NetworkStats} into this object.
298905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
299905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public void combineAllValues(NetworkStats another) {
300905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        NetworkStats.Entry entry = null;
301905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < another.size; i++) {
302905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry = another.getValues(i, entry);
303905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            combineValues(entry);
304905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
305905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
306905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
307905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
3089a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * Find first stats index that matches the requested parameters.
3099a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
310b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public int findIndex(String iface, int uid, int set, int tag) {
3114a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        for (int i = 0; i < size; i++) {
312163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
313163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                    && Objects.equal(iface, this.iface[i])) {
314163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                return i;
315163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
316163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
317163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        return -1;
318163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
319163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
320163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    /**
321163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * Find first stats index that matches the requested parameters, starting
322163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * search around the hinted index as an optimization.
323163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     */
324163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    // @VisibleForTesting
325163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
326163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        for (int offset = 0; offset < size; offset++) {
327163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int halfOffset = offset / 2;
328163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
329163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            // search outwards from hint index, alternating forward and backward
330163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int i;
331163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (offset % 2 == 0) {
332163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                i = (hintIndex + halfOffset) % size;
333163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            } else {
334163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                i = (size + hintIndex - halfOffset - 1) % size;
335163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
336163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
337163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
338163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                    && Objects.equal(iface, this.iface[i])) {
3399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey                return i;
3409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            }
3419a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
3429a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return -1;
3439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
3449a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
345eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    /**
346a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Splice in {@link #operations} from the given {@link NetworkStats} based
347a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
348a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * since operation counts are at data layer.
349a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
350a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void spliceOperationsFrom(NetworkStats stats) {
351a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        for (int i = 0; i < size; i++) {
352b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
353a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (j == -1) {
354a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = 0;
355a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            } else {
356a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = stats.operations[j];
357a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
358a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
359a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
360a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
361a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
36275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Return list of unique interfaces known by this data structure.
36375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
36461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public String[] getUniqueIfaces() {
36575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final HashSet<String> ifaces = new HashSet<String>();
36675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (String iface : this.iface) {
36775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (iface != IFACE_ALL) {
36875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                ifaces.add(iface);
36975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
37075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
37175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return ifaces.toArray(new String[ifaces.size()]);
37275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
37375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
37475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
37561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * Return list of unique UIDs known by this data structure.
37661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
37761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public int[] getUniqueUids() {
37861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final SparseBooleanArray uids = new SparseBooleanArray();
37961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int uid : this.uid) {
38061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            uids.put(uid, true);
38161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
38261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
38361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int size = uids.size();
38461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int[] result = new int[size];
38561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int i = 0; i < size; i++) {
38661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            result[i] = uids.keyAt(i);
38761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
38861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return result;
38961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
39061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
39161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
3928e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * Return total bytes represented by this snapshot object, usually used when
3938e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
3948e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     */
3958e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    public long getTotalBytes() {
39607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = getTotal(null);
39707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry.rxBytes + entry.txBytes;
39807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    }
39907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
40007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    /**
40107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     * Return total of all fields represented by this snapshot object.
40207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     */
40307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    public Entry getTotal(Entry recycle) {
4041059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return getTotal(recycle, null, UID_ALL);
4051059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4061059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4071059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4081059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4091059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #uid}.
4101059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4111059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public Entry getTotal(Entry recycle, int limitUid) {
4121059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return getTotal(recycle, null, limitUid);
4131059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4141059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4151059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4161059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4171059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #iface}.
4181059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4191059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
4201059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return getTotal(recycle, limitIface, UID_ALL);
4211059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4221059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4231059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4241059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4251059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #iface} and {@link #uid}.
4261059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     *
4271059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * @param limitIface Set of {@link #iface} to include in total; or {@code
4281059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     *            null} to include all ifaces.
4291059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4301059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    private Entry getTotal(Entry recycle, HashSet<String> limitIface, int limitUid) {
43107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
43207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
43307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.iface = IFACE_ALL;
4341059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.uid = limitUid;
43507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.set = SET_ALL;
43607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.tag = TAG_NONE;
43707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxBytes = 0;
43807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxPackets = 0;
43907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txBytes = 0;
44007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txPackets = 0;
4411059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.operations = 0;
44207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
4438e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        for (int i = 0; i < size; i++) {
4441059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
4451059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
4461059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4471059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            if (matchesUid && matchesIface) {
4481059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                // skip specific tags, since already counted in TAG_NONE
4491059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                if (tag[i] != TAG_NONE) continue;
4501059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4511059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.rxBytes += rxBytes[i];
4521059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.rxPackets += rxPackets[i];
4531059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.txBytes += txBytes[i];
4541059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.txPackets += txPackets[i];
4551059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.operations += operations[i];
4561059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            }
4578e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        }
45807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry;
4598e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    }
4608e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
4618e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    /**
462eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
463eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
464eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * time, and that none of them have disappeared.
465eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     */
466163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
467d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey        return subtract(value, false);
468d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    }
469d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey
470d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    /**
471d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
472d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
473d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * time, and that none of them have disappeared.
474d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     *
475d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * @param clampNonMonotonic When non-monotonic stats are found, just clamp
476d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     *            to 0 instead of throwing {@link NonMonotonicException}.
477d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     */
478d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic)
479d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey            throws NonMonotonicException {
48075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
481163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        if (deltaRealtime < 0) {
4823359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            throw new NonMonotonicException(this, value);
48375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
484eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
48575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // result will have our rows, and elapsed time between snapshots
486fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = new Entry();
4874a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        final NetworkStats result = new NetworkStats(deltaRealtime, size);
4884a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        for (int i = 0; i < size; i++) {
489fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            entry.iface = iface[i];
490fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            entry.uid = uid[i];
491b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            entry.set = set[i];
492fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            entry.tag = tag[i];
493eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
494eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            // find remote row that matches, and subtract
495163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int j = value.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
496eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            if (j == -1) {
497eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // newly appearing row, return entire value
498d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.rxBytes = rxBytes[i];
499fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.rxPackets = rxPackets[i];
500d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.txBytes = txBytes[i];
501fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.txPackets = txPackets[i];
502a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                entry.operations = operations[i];
503eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            } else {
504eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // existing row, subtract remote value
505d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.rxBytes = rxBytes[i] - value.rxBytes[j];
506fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.rxPackets = rxPackets[i] - value.rxPackets[j];
507d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.txBytes = txBytes[i] - value.txBytes[j];
508fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.txPackets = txPackets[i] - value.txPackets[j];
509a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                entry.operations = operations[i] - value.operations[j];
510163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
511163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
512163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                        || entry.txPackets < 0 || entry.operations < 0) {
513d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                    if (clampNonMonotonic) {
514d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                        entry.rxBytes = Math.max(entry.rxBytes, 0);
515d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                        entry.rxPackets = Math.max(entry.rxPackets, 0);
516d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                        entry.txBytes = Math.max(entry.txBytes, 0);
517d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                        entry.txPackets = Math.max(entry.txPackets, 0);
518d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                        entry.operations = Math.max(entry.operations, 0);
519d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                    } else {
520d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                        throw new NonMonotonicException(this, i, value, j);
521d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                    }
5223f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey                }
523eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            }
524fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
525fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            result.addValues(entry);
526eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        }
527eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
5284a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return result;
5299a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
5309a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
531905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
532905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Return total statistics grouped by {@link #iface}; doesn't mutate the
533905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * original structure.
534905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
535905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public NetworkStats groupedByIface() {
536905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
537905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
538905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final Entry entry = new Entry();
539905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.uid = UID_ALL;
540905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.set = SET_ALL;
541905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.tag = TAG_NONE;
542905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.operations = 0L;
543905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
544905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < size; i++) {
545905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
546905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            if (tag[i] != TAG_NONE) continue;
547905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
548905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.iface = iface[i];
549905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxBytes = rxBytes[i];
550905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxPackets = rxPackets[i];
551905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txBytes = txBytes[i];
552905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txPackets = txPackets[i];
553905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            stats.combineValues(entry);
554905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
555905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
556905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        return stats;
557905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
558905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
5591059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
5601059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total statistics grouped by {@link #uid}; doesn't mutate the
5611059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * original structure.
5621059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
5631059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public NetworkStats groupedByUid() {
5641059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
5651059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5661059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        final Entry entry = new Entry();
5671059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.iface = IFACE_ALL;
5681059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.set = SET_ALL;
5691059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.tag = TAG_NONE;
5701059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5711059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        for (int i = 0; i < size; i++) {
5721059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
5731059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            if (tag[i] != TAG_NONE) continue;
5741059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5751059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.uid = uid[i];
5761059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.rxBytes = rxBytes[i];
5771059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.rxPackets = rxPackets[i];
5781059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.txBytes = txBytes[i];
5791059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.txPackets = txPackets[i];
5801059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.operations = operations[i];
5811059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            stats.combineValues(entry);
5821059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        }
5831059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5841059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return stats;
5851059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
5861059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
587163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    /**
588163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * Return all rows except those attributed to the requested UID; doesn't
589163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * mutate the original structure.
590163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     */
591163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public NetworkStats withoutUid(int uid) {
592163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
593163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
594163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        Entry entry = new Entry();
595163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        for (int i = 0; i < size; i++) {
596163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            entry = getValues(i, entry);
597163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (entry.uid != uid) {
598163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                stats.addValues(entry);
599163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
600163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
601163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
602163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        return stats;
603163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
604163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
6059a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public void dump(String prefix, PrintWriter pw) {
6069a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print(prefix);
6079a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
608fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        for (int i = 0; i < size; i++) {
6099a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(prefix);
6103359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            pw.print("  ["); pw.print(i); pw.print("]");
6113359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            pw.print(" iface="); pw.print(iface[i]);
6129a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(" uid="); pw.print(uid[i]);
613b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" set="); pw.print(setToString(set[i]));
614b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" tag="); pw.print(tagToString(tag[i]));
615d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" rxBytes="); pw.print(rxBytes[i]);
616fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            pw.print(" rxPackets="); pw.print(rxPackets[i]);
617d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" txBytes="); pw.print(txBytes[i]);
618a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" txPackets="); pw.print(txPackets[i]);
619a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" operations="); pw.println(operations[i]);
6209a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6219a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
6229a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
623b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
624b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #set} value.
625b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
626b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String setToString(int set) {
627b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        switch (set) {
628b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_ALL:
629b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "ALL";
630b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_DEFAULT:
631b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "DEFAULT";
632b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_FOREGROUND:
633b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "FOREGROUND";
634b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            default:
635b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "UNKNOWN";
636b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
637b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
638b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
639b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
640b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #tag} value.
641b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
642b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String tagToString(int tag) {
643b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return "0x" + Integer.toHexString(tag);
644b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
645b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
6469a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    @Override
6479a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public String toString() {
6489a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
6499a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        dump("", new PrintWriter(writer));
6509a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return writer.toString();
6519a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
6529a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
6539a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /** {@inheritDoc} */
654eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    public int describeContents() {
655eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        return 0;
656eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
657eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
6589a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
6599a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats createFromParcel(Parcel in) {
6609a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats(in);
6619a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6629a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
6639a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats[] newArray(int size) {
6649a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats[size];
6659a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6669a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    };
667163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
668163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public static class NonMonotonicException extends Exception {
669163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        public final NetworkStats left;
670163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        public final NetworkStats right;
671163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        public final int leftIndex;
672163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        public final int rightIndex;
673163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
6743359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey        public NonMonotonicException(NetworkStats left, NetworkStats right) {
6753359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            this(left, -1, right, -1);
6763359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey        }
6773359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey
678163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        public NonMonotonicException(
679163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
680163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            this.left = checkNotNull(left, "missing left");
681163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            this.right = checkNotNull(right, "missing right");
682163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            this.leftIndex = leftIndex;
683163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            this.rightIndex = rightIndex;
684163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
685163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
6869a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey}
687