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
199a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.Parcel;
209a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.Parcelable;
219a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport android.os.SystemClock;
2261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport android.util.SparseBooleanArray;
239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
24daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
25a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport com.android.internal.util.Objects;
26a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
279a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.CharArrayWriter;
289a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeyimport java.io.PrintWriter;
294a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkeyimport java.util.Arrays;
3075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.HashSet;
319a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
329a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey/**
3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of active network statistics. Can contain summary details across
3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * all interfaces, or details with per-UID granularity. Internally stores data
3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * as a large table, closely matching {@code /proc/} data format. This structure
3675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * optimizes for rapid in-memory comparison, but consider using
3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link NetworkStatsHistory} when persisting.
389a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey *
399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey * @hide
409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey */
419a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkeypublic class NetworkStats implements Parcelable {
4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #iface} value when interface details unavailable. */
439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final String IFACE_ALL = null;
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #uid} value when UID details unavailable. */
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final int UID_ALL = -1;
46b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value when all sets combined. */
47b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_ALL = -1;
48b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where background data is accounted. */
49b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_DEFAULT = 0;
50b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where foreground data is accounted. */
51b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_FOREGROUND = 1;
52b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #tag} value for total data across all tags. */
531b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    public static final int TAG_NONE = 0;
54eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
55163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    // TODO: move fields to "mVariable" notation
56163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
579a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
589a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
599a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * generated.
609a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
61d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private final long elapsedRealtime;
62d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int size;
63d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private String[] iface;
64d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int[] uid;
65b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    private int[] set;
66d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int[] tag;
67d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
68d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxPackets;
69d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
70d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txPackets;
7163d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
72fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
73fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public static class Entry {
74fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public String iface;
75fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public int uid;
76b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        public int set;
77fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public int tag;
78fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long rxBytes;
79fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long rxPackets;
80fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long txBytes;
81fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long txPackets;
8263d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
83d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
84d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public Entry() {
85b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
8663d27a9233fed934340231f438493746084a681dJeff Sharkey        }
8763d27a9233fed934340231f438493746084a681dJeff Sharkey
8863d27a9233fed934340231f438493746084a681dJeff Sharkey        public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
89b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
90b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                    operations);
91d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        }
92d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
93b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
94b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                long txBytes, long txPackets, long operations) {
95d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.iface = iface;
96d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.uid = uid;
97b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this.set = set;
98d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.tag = tag;
99d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.rxBytes = rxBytes;
100d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.rxPackets = rxPackets;
101d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.txBytes = txBytes;
102d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.txPackets = txPackets;
103a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            this.operations = operations;
104d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        }
105b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey
10663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean isNegative() {
10763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
10863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
10963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean isEmpty() {
11163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    && operations == 0;
11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        public void add(Entry another) {
11670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.rxBytes += another.rxBytes;
11770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.rxPackets += another.rxPackets;
11870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.txBytes += another.txBytes;
11970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.txPackets += another.txPackets;
12070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.operations += another.operations;
12170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        }
12270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
123b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        @Override
124b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        public String toString() {
125b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            final StringBuilder builder = new StringBuilder();
126b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append("iface=").append(iface);
127b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" uid=").append(uid);
128b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" set=").append(setToString(set));
129b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" tag=").append(tagToString(tag));
130b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxBytes=").append(rxBytes);
131b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxPackets=").append(rxPackets);
132b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txBytes=").append(txBytes);
133b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txPackets=").append(txPackets);
134b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" operations=").append(operations);
135b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            return builder.toString();
136b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        }
137fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
1389a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1394a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStats(long elapsedRealtime, int initialSize) {
1409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        this.elapsedRealtime = elapsedRealtime;
1414a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.size = 0;
1424a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.iface = new String[initialSize];
1434a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.uid = new int[initialSize];
144b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        this.set = new int[initialSize];
1451b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        this.tag = new int[initialSize];
146d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.rxBytes = new long[initialSize];
147fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.rxPackets = new long[initialSize];
148d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.txBytes = new long[initialSize];
149fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.txPackets = new long[initialSize];
15063d27a9233fed934340231f438493746084a681dJeff Sharkey        this.operations = new long[initialSize];
1519a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1529a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1539a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public NetworkStats(Parcel parcel) {
1549a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        elapsedRealtime = parcel.readLong();
1554a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size = parcel.readInt();
1569a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        iface = parcel.createStringArray();
1579a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        uid = parcel.createIntArray();
158b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set = parcel.createIntArray();
1591b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        tag = parcel.createIntArray();
160d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes = parcel.createLongArray();
161fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets = parcel.createLongArray();
162d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes = parcel.createLongArray();
163fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets = parcel.createLongArray();
16463d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = parcel.createLongArray();
165a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
166a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
167bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
168a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void writeToParcel(Parcel dest, int flags) {
169a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLong(elapsedRealtime);
170a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeInt(size);
171a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeStringArray(iface);
172a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(uid);
173b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        dest.writeIntArray(set);
174a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(tag);
175a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxBytes);
176a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxPackets);
177a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txBytes);
178a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txPackets);
17963d27a9233fed934340231f438493746084a681dJeff Sharkey        dest.writeLongArray(operations);
1809a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1819a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1824abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    @Override
1834abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    public NetworkStats clone() {
1844abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
1854abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        NetworkStats.Entry entry = null;
1864abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        for (int i = 0; i < size; i++) {
1874abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey            entry = getValues(i, entry);
1884abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey            clone.addValues(entry);
1894abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        }
1904abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        return clone;
1914abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    }
1924abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey
193b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    // @VisibleForTesting
194b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addIfaceValues(
195b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
196b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(
197b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
198a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
199a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
200b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    // @VisibleForTesting
201b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
202b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
203b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(new Entry(
204b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
205fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
206fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
207fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
208fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
209fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * object can be recycled across multiple calls.
210fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
211fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public NetworkStats addValues(Entry entry) {
2124a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (size >= this.iface.length) {
213fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            final int newLength = Math.max(iface.length, 10) * 3 / 2;
214fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            iface = Arrays.copyOf(iface, newLength);
215fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            uid = Arrays.copyOf(uid, newLength);
216b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            set = Arrays.copyOf(set, newLength);
217fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            tag = Arrays.copyOf(tag, newLength);
218d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes = Arrays.copyOf(rxBytes, newLength);
219fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            rxPackets = Arrays.copyOf(rxPackets, newLength);
220d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes = Arrays.copyOf(txBytes, newLength);
221fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            txPackets = Arrays.copyOf(txPackets, newLength);
222a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations = Arrays.copyOf(operations, newLength);
2239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
2249a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
225fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        iface[size] = entry.iface;
226fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        uid[size] = entry.uid;
227b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set[size] = entry.set;
228fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        tag[size] = entry.tag;
229d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes[size] = entry.rxBytes;
230fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets[size] = entry.rxPackets;
231d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes[size] = entry.txBytes;
232fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets[size] = entry.txPackets;
233a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        operations[size] = entry.operations;
2344a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size++;
2359a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2364a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return this;
2379a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
2389a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2391b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    /**
240fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Return specific stats entry.
241fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
242fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public Entry getValues(int i, Entry recycle) {
243fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
244fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.iface = iface[i];
245fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.uid = uid[i];
246b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        entry.set = set[i];
247fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.tag = tag[i];
248d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.rxBytes = rxBytes[i];
249fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.rxPackets = rxPackets[i];
250d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.txBytes = txBytes[i];
251fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.txPackets = txPackets[i];
252a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        entry.operations = operations[i];
253fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return entry;
254fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
255fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
256fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public long getElapsedRealtime() {
257fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return elapsedRealtime;
258fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
259fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
2601059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
2611059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return age of this {@link NetworkStats} object with respect to
2621059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * {@link SystemClock#elapsedRealtime()}.
2631059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
2641059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public long getElapsedRealtimeAge() {
2651059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return SystemClock.elapsedRealtime() - elapsedRealtime;
2661059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
2671059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
268fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public int size() {
269fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return size;
270fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
271fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
272d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    // @VisibleForTesting
273d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int internalSize() {
274d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return iface.length;
275d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
276d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
277b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    @Deprecated
278d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
27963d27a9233fed934340231f438493746084a681dJeff Sharkey            long txBytes, long txPackets, long operations) {
280a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        return combineValues(
281b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
282b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
283b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
284b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
285b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
286b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return combineValues(new Entry(
287b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
288d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
289d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
290fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
2911b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     * Combine given values with an existing row, or create a new row if
292b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * {@link #findIndex(String, int, int, int)} is unable to find match. Can
293b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * also be used to subtract values from existing rows.
2941b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     */
295d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(Entry entry) {
296b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
2971b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        if (i == -1) {
2981b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            // only create new entry when positive contribution
299d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            addValues(entry);
3001b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        } else {
301d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes[i] += entry.rxBytes;
302d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxPackets[i] += entry.rxPackets;
303d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes[i] += entry.txBytes;
304d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txPackets[i] += entry.txPackets;
305a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations[i] += entry.operations;
3061b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
3071b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        return this;
308eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
309eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
3109a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
311905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Combine all values from another {@link NetworkStats} into this object.
312905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
313905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public void combineAllValues(NetworkStats another) {
314905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        NetworkStats.Entry entry = null;
315905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < another.size; i++) {
316905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry = another.getValues(i, entry);
317905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            combineValues(entry);
318905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
319905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
320905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
321905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
3229a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * Find first stats index that matches the requested parameters.
3239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
324b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public int findIndex(String iface, int uid, int set, int tag) {
3254a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        for (int i = 0; i < size; i++) {
326163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
327163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                    && Objects.equal(iface, this.iface[i])) {
328163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                return i;
329163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
330163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
331163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        return -1;
332163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
333163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
334163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    /**
335163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * Find first stats index that matches the requested parameters, starting
336163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * search around the hinted index as an optimization.
337163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     */
338163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    // @VisibleForTesting
339163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
340163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        for (int offset = 0; offset < size; offset++) {
341163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int halfOffset = offset / 2;
342163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
343163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            // search outwards from hint index, alternating forward and backward
344163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int i;
345163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (offset % 2 == 0) {
346163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                i = (hintIndex + halfOffset) % size;
347163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            } else {
348163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                i = (size + hintIndex - halfOffset - 1) % size;
349163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
350163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
351163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
352163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                    && Objects.equal(iface, this.iface[i])) {
3539a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey                return i;
3549a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            }
3559a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
3569a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return -1;
3579a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
3589a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
359eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    /**
360a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Splice in {@link #operations} from the given {@link NetworkStats} based
361a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
362a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * since operation counts are at data layer.
363a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
364a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void spliceOperationsFrom(NetworkStats stats) {
365a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        for (int i = 0; i < size; i++) {
36621a547823de52806de48f70b8360353344a5ad88Jeff Sharkey            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]);
367a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (j == -1) {
368a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = 0;
369a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            } else {
370a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = stats.operations[j];
371a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
372a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
373a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
374a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
375a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
37675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Return list of unique interfaces known by this data structure.
37775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
37861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public String[] getUniqueIfaces() {
37975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final HashSet<String> ifaces = new HashSet<String>();
38075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (String iface : this.iface) {
38175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (iface != IFACE_ALL) {
38275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                ifaces.add(iface);
38375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
38475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
38575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return ifaces.toArray(new String[ifaces.size()]);
38675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
38775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
38875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
38961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * Return list of unique UIDs known by this data structure.
39061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
39161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public int[] getUniqueUids() {
39261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final SparseBooleanArray uids = new SparseBooleanArray();
39361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int uid : this.uid) {
39461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            uids.put(uid, true);
39561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
39661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
39761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int size = uids.size();
39861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int[] result = new int[size];
39961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int i = 0; i < size; i++) {
40061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            result[i] = uids.keyAt(i);
40161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
40261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return result;
40361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
40461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
40561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
4068e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * Return total bytes represented by this snapshot object, usually used when
4078e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
4088e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     */
4098e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    public long getTotalBytes() {
41007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = getTotal(null);
41107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry.rxBytes + entry.txBytes;
41207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    }
41307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
41407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    /**
41507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     * Return total of all fields represented by this snapshot object.
41607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     */
41707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    public Entry getTotal(Entry recycle) {
41863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, null, UID_ALL, false);
4191059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4201059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4211059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4221059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4231059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #uid}.
4241059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4251059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public Entry getTotal(Entry recycle, int limitUid) {
42663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, null, limitUid, false);
4271059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4281059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4291059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4301059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4311059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #iface}.
4321059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4331059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
43463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, limitIface, UID_ALL, false);
43563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
43663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
43763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public Entry getTotalIncludingTags(Entry recycle) {
43863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, null, UID_ALL, true);
4391059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4401059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4411059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4421059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4431059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #iface} and {@link #uid}.
4441059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     *
4451059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * @param limitIface Set of {@link #iface} to include in total; or {@code
4461059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     *            null} to include all ifaces.
4471059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
44863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private Entry getTotal(
44963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
45007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
45107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
45207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.iface = IFACE_ALL;
4531059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.uid = limitUid;
45407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.set = SET_ALL;
45507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.tag = TAG_NONE;
45607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxBytes = 0;
45707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxPackets = 0;
45807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txBytes = 0;
45907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txPackets = 0;
4601059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.operations = 0;
46107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
4628e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        for (int i = 0; i < size; i++) {
4631059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
4641059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
4651059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4661059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            if (matchesUid && matchesIface) {
4671059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                // skip specific tags, since already counted in TAG_NONE
46863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (tag[i] != TAG_NONE && !includeTags) continue;
4691059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4701059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.rxBytes += rxBytes[i];
4711059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.rxPackets += rxPackets[i];
4721059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.txBytes += txBytes[i];
4731059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.txPackets += txPackets[i];
4741059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.operations += operations[i];
4751059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            }
4768e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        }
47707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry;
4788e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    }
4798e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
4808e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    /**
481eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
482eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
483eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * time, and that none of them have disappeared.
484eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     */
4855a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey    public NetworkStats subtract(NetworkStats right) {
48663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return subtract(this, right, null, null);
487d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    }
488d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey
489d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    /**
4905a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * Subtract the two given {@link NetworkStats} objects, returning the delta
491d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
492d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * time, and that none of them have disappeared.
4935a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * <p>
4945a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * If counters have rolled backwards, they are clamped to {@code 0} and
4955a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * reported to the given {@link NonMonotonicObserver}.
496d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     */
49763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public static <C> NetworkStats subtract(
49863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) {
4995a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
500163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        if (deltaRealtime < 0) {
5015a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            if (observer != null) {
50263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                observer.foundNonMonotonic(left, -1, right, -1, cookie);
5035a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            }
5045a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            deltaRealtime = 0;
50575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
506eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
50775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // result will have our rows, and elapsed time between snapshots
508fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = new Entry();
5095a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        final NetworkStats result = new NetworkStats(deltaRealtime, left.size);
5105a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        for (int i = 0; i < left.size; i++) {
5115a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.iface = left.iface[i];
5125a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.uid = left.uid[i];
5135a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.set = left.set[i];
5145a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.tag = left.tag[i];
515eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
516eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            // find remote row that matches, and subtract
5175a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
518eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            if (j == -1) {
519eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // newly appearing row, return entire value
5205a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxBytes = left.rxBytes[i];
5215a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxPackets = left.rxPackets[i];
5225a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txBytes = left.txBytes[i];
5235a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txPackets = left.txPackets[i];
5245a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.operations = left.operations[i];
525eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            } else {
526eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // existing row, subtract remote value
5275a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxBytes = left.rxBytes[i] - right.rxBytes[j];
5285a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxPackets = left.rxPackets[i] - right.rxPackets[j];
5295a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txBytes = left.txBytes[i] - right.txBytes[j];
5305a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txPackets = left.txPackets[i] - right.txPackets[j];
5315a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.operations = left.operations[i] - right.operations[j];
532163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
533163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
534163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                        || entry.txPackets < 0 || entry.operations < 0) {
5355a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    if (observer != null) {
53663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        observer.foundNonMonotonic(left, i, right, j, cookie);
537d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                    }
5385a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.rxBytes = Math.max(entry.rxBytes, 0);
5395a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.rxPackets = Math.max(entry.rxPackets, 0);
5405a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.txBytes = Math.max(entry.txBytes, 0);
5415a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.txPackets = Math.max(entry.txPackets, 0);
5425a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.operations = Math.max(entry.operations, 0);
5433f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey                }
544eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            }
545fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
546fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            result.addValues(entry);
547eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        }
548eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
5494a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return result;
5509a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
5519a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
552905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
553905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Return total statistics grouped by {@link #iface}; doesn't mutate the
554905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * original structure.
555905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
556905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public NetworkStats groupedByIface() {
557905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
558905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
559905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final Entry entry = new Entry();
560905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.uid = UID_ALL;
561905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.set = SET_ALL;
562905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.tag = TAG_NONE;
563905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.operations = 0L;
564905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
565905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < size; i++) {
566905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
567905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            if (tag[i] != TAG_NONE) continue;
568905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
569905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.iface = iface[i];
570905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxBytes = rxBytes[i];
571905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxPackets = rxPackets[i];
572905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txBytes = txBytes[i];
573905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txPackets = txPackets[i];
574905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            stats.combineValues(entry);
575905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
576905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
577905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        return stats;
578905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
579905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
5801059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
5811059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total statistics grouped by {@link #uid}; doesn't mutate the
5821059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * original structure.
5831059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
5841059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public NetworkStats groupedByUid() {
5851059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
5861059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5871059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        final Entry entry = new Entry();
5881059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.iface = IFACE_ALL;
5891059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.set = SET_ALL;
5901059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.tag = TAG_NONE;
5911059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5921059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        for (int i = 0; i < size; i++) {
5931059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
5941059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            if (tag[i] != TAG_NONE) continue;
5951059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
5961059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.uid = uid[i];
5971059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.rxBytes = rxBytes[i];
5981059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.rxPackets = rxPackets[i];
5991059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.txBytes = txBytes[i];
6001059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.txPackets = txPackets[i];
6011059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.operations = operations[i];
6021059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            stats.combineValues(entry);
6031059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        }
6041059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
6051059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return stats;
6061059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
6071059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
608163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    /**
609163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * Return all rows except those attributed to the requested UID; doesn't
610163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * mutate the original structure.
611163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     */
612daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey    public NetworkStats withoutUids(int[] uids) {
613163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
614163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
615163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        Entry entry = new Entry();
616163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        for (int i = 0; i < size; i++) {
617163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            entry = getValues(i, entry);
618daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            if (!ArrayUtils.contains(uids, entry.uid)) {
619163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                stats.addValues(entry);
620163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
621163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
622163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
623163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        return stats;
624163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
625163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
6269a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public void dump(String prefix, PrintWriter pw) {
6279a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print(prefix);
6289a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
629fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        for (int i = 0; i < size; i++) {
6309a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(prefix);
6313359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            pw.print("  ["); pw.print(i); pw.print("]");
6323359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            pw.print(" iface="); pw.print(iface[i]);
6339a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(" uid="); pw.print(uid[i]);
634b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" set="); pw.print(setToString(set[i]));
635b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" tag="); pw.print(tagToString(tag[i]));
636d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" rxBytes="); pw.print(rxBytes[i]);
637fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            pw.print(" rxPackets="); pw.print(rxPackets[i]);
638d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" txBytes="); pw.print(txBytes[i]);
639a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" txPackets="); pw.print(txPackets[i]);
640a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" operations="); pw.println(operations[i]);
6419a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6429a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
6439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
644b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
645b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #set} value.
646b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
647b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String setToString(int set) {
648b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        switch (set) {
649b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_ALL:
650b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "ALL";
651b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_DEFAULT:
652b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "DEFAULT";
653b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_FOREGROUND:
654b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "FOREGROUND";
655b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            default:
656b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "UNKNOWN";
657b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
658b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
659b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
660b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
661b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #tag} value.
662b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
663b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String tagToString(int tag) {
664b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return "0x" + Integer.toHexString(tag);
665b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
666b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
6679a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    @Override
6689a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public String toString() {
6699a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
6709a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        dump("", new PrintWriter(writer));
6719a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return writer.toString();
6729a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
6739a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
674bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
675eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    public int describeContents() {
676eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        return 0;
677eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
678eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
6799a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
680bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
6819a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats createFromParcel(Parcel in) {
6829a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats(in);
6839a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6849a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
685bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
6869a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats[] newArray(int size) {
6879a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats[size];
6889a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6899a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    };
690163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
69163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public interface NonMonotonicObserver<C> {
6925a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        public void foundNonMonotonic(
69363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
694163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
6959a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey}
696