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
248b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.VisibleForTesting;
25daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
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 {
4375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #iface} value when interface details unavailable. */
449a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final String IFACE_ALL = null;
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #uid} value when UID details unavailable. */
4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final int UID_ALL = -1;
47b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value when all sets combined. */
48b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_ALL = -1;
49b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where background data is accounted. */
50b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_DEFAULT = 0;
51b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where foreground data is accounted. */
52b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_FOREGROUND = 1;
53b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #tag} value for total data across all tags. */
541b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    public static final int TAG_NONE = 0;
55eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
56163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    // TODO: move fields to "mVariable" notation
57163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
589a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
599a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * {@link SystemClock#elapsedRealtime()} timestamp when this data was
609a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * generated.
619a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
62d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private final long elapsedRealtime;
63d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int size;
64d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private String[] iface;
65d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int[] uid;
66b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    private int[] set;
67d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int[] tag;
68d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
69d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxPackets;
70d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
71d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txPackets;
7263d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
73fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
74fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public static class Entry {
75fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public String iface;
76fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public int uid;
77b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        public int set;
78fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public int tag;
79fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long rxBytes;
80fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long rxPackets;
81fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long txBytes;
82fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        public long txPackets;
8363d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
84d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
85d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public Entry() {
86b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
8763d27a9233fed934340231f438493746084a681dJeff Sharkey        }
8863d27a9233fed934340231f438493746084a681dJeff Sharkey
8963d27a9233fed934340231f438493746084a681dJeff Sharkey        public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
90b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
91b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                    operations);
92d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        }
93d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
94b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
95b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                long txBytes, long txPackets, long operations) {
96d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.iface = iface;
97d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.uid = uid;
98b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            this.set = set;
99d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.tag = tag;
100d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.rxBytes = rxBytes;
101d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.rxPackets = rxPackets;
102d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.txBytes = txBytes;
103d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            this.txPackets = txPackets;
104a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            this.operations = operations;
105d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        }
106b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey
10763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean isNegative() {
10863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
10963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
11063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        public boolean isEmpty() {
11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                    && operations == 0;
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        }
11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        public void add(Entry another) {
11770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.rxBytes += another.rxBytes;
11870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.rxPackets += another.rxPackets;
11970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.txBytes += another.txBytes;
12070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.txPackets += another.txPackets;
12170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            this.operations += another.operations;
12270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        }
12370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
124b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        @Override
125b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        public String toString() {
126b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            final StringBuilder builder = new StringBuilder();
127b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append("iface=").append(iface);
128b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" uid=").append(uid);
129b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" set=").append(setToString(set));
130b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" tag=").append(tagToString(tag));
131b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxBytes=").append(rxBytes);
132b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxPackets=").append(rxPackets);
133b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txBytes=").append(txBytes);
134b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txPackets=").append(txPackets);
135b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" operations=").append(operations);
136b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            return builder.toString();
137b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        }
1389a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey
1399a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey        @Override
1409a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey        public boolean equals(Object o) {
1419a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey            if (o instanceof Entry) {
1429a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey                final Entry e = (Entry) o;
1439a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey                return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes
1449a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey                        && rxPackets == e.rxPackets && txBytes == e.txBytes
1459a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey                        && txPackets == e.txPackets && operations == e.operations
1469a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey                        && iface.equals(e.iface);
1479a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey            }
1489a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey            return false;
1499a2c2a6da90abbcc9a064c20e93ed885651f4ae1Jeff Sharkey        }
150fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
1519a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1524a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStats(long elapsedRealtime, int initialSize) {
1539a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        this.elapsedRealtime = elapsedRealtime;
1544a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.size = 0;
1554a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.iface = new String[initialSize];
1564a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.uid = new int[initialSize];
157b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        this.set = new int[initialSize];
1581b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        this.tag = new int[initialSize];
159d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.rxBytes = new long[initialSize];
160fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.rxPackets = new long[initialSize];
161d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.txBytes = new long[initialSize];
162fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.txPackets = new long[initialSize];
16363d27a9233fed934340231f438493746084a681dJeff Sharkey        this.operations = new long[initialSize];
1649a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1659a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1669a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public NetworkStats(Parcel parcel) {
1679a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        elapsedRealtime = parcel.readLong();
1684a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size = parcel.readInt();
1699a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        iface = parcel.createStringArray();
1709a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        uid = parcel.createIntArray();
171b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set = parcel.createIntArray();
1721b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        tag = parcel.createIntArray();
173d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes = parcel.createLongArray();
174fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets = parcel.createLongArray();
175d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes = parcel.createLongArray();
176fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets = parcel.createLongArray();
17763d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = parcel.createLongArray();
178a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
179a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
180bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
181a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void writeToParcel(Parcel dest, int flags) {
182a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLong(elapsedRealtime);
183a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeInt(size);
184a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeStringArray(iface);
185a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(uid);
186b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        dest.writeIntArray(set);
187a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(tag);
188a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxBytes);
189a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxPackets);
190a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txBytes);
191a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txPackets);
19263d27a9233fed934340231f438493746084a681dJeff Sharkey        dest.writeLongArray(operations);
1939a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1949a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1954abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    @Override
1964abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    public NetworkStats clone() {
1974abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
1984abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        NetworkStats.Entry entry = null;
1994abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        for (int i = 0; i < size; i++) {
2004abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey            entry = getValues(i, entry);
2014abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey            clone.addValues(entry);
2024abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        }
2034abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey        return clone;
2044abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey    }
2054abb1b8ef64dc4cd71966b59dc5d72a15055bf13Jeff Sharkey
2068b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @VisibleForTesting
207b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addIfaceValues(
208b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
209b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(
210b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
211a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
212a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
2138b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @VisibleForTesting
214b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
215b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
216b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(new Entry(
217b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
218fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
219fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
220fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
221fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
222fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * object can be recycled across multiple calls.
223fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
224fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public NetworkStats addValues(Entry entry) {
2254a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (size >= this.iface.length) {
226fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            final int newLength = Math.max(iface.length, 10) * 3 / 2;
227fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            iface = Arrays.copyOf(iface, newLength);
228fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            uid = Arrays.copyOf(uid, newLength);
229b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            set = Arrays.copyOf(set, newLength);
230fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            tag = Arrays.copyOf(tag, newLength);
231d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes = Arrays.copyOf(rxBytes, newLength);
232fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            rxPackets = Arrays.copyOf(rxPackets, newLength);
233d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes = Arrays.copyOf(txBytes, newLength);
234fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            txPackets = Arrays.copyOf(txPackets, newLength);
235a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations = Arrays.copyOf(operations, newLength);
2369a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
2379a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
238fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        iface[size] = entry.iface;
239fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        uid[size] = entry.uid;
240b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set[size] = entry.set;
241fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        tag[size] = entry.tag;
242d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes[size] = entry.rxBytes;
243fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets[size] = entry.rxPackets;
244d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes[size] = entry.txBytes;
245fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets[size] = entry.txPackets;
246a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        operations[size] = entry.operations;
2474a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size++;
2489a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2494a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return this;
2509a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
2519a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2521b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    /**
253fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Return specific stats entry.
254fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
255fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public Entry getValues(int i, Entry recycle) {
256fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
257fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.iface = iface[i];
258fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.uid = uid[i];
259b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        entry.set = set[i];
260fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.tag = tag[i];
261d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.rxBytes = rxBytes[i];
262fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.rxPackets = rxPackets[i];
263d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.txBytes = txBytes[i];
264fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.txPackets = txPackets[i];
265a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        entry.operations = operations[i];
266fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return entry;
267fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
268fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
269fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public long getElapsedRealtime() {
270fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return elapsedRealtime;
271fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
272fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
2731059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
2741059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return age of this {@link NetworkStats} object with respect to
2751059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * {@link SystemClock#elapsedRealtime()}.
2761059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
2771059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public long getElapsedRealtimeAge() {
2781059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return SystemClock.elapsedRealtime() - elapsedRealtime;
2791059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
2801059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
281fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public int size() {
282fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return size;
283fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
284fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
2858b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @VisibleForTesting
286d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int internalSize() {
287d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return iface.length;
288d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
289d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
290b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    @Deprecated
291d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
29263d27a9233fed934340231f438493746084a681dJeff Sharkey            long txBytes, long txPackets, long operations) {
293a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        return combineValues(
294b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
295b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
296b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
297b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
298b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
299b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return combineValues(new Entry(
300b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
301d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
302d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
303fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
3041b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     * Combine given values with an existing row, or create a new row if
305b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * {@link #findIndex(String, int, int, int)} is unable to find match. Can
306b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * also be used to subtract values from existing rows.
3071b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     */
308d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(Entry entry) {
309b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
3101b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        if (i == -1) {
3111b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            // only create new entry when positive contribution
312d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            addValues(entry);
3131b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        } else {
314d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes[i] += entry.rxBytes;
315d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxPackets[i] += entry.rxPackets;
316d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes[i] += entry.txBytes;
317d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txPackets[i] += entry.txPackets;
318a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations[i] += entry.operations;
3191b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
3201b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        return this;
321eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
322eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
3239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
324905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Combine all values from another {@link NetworkStats} into this object.
325905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
326905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public void combineAllValues(NetworkStats another) {
327905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        NetworkStats.Entry entry = null;
328905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < another.size; i++) {
329905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry = another.getValues(i, entry);
330905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            combineValues(entry);
331905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
332905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
333905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
334905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
3359a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * Find first stats index that matches the requested parameters.
3369a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
337b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public int findIndex(String iface, int uid, int set, int tag) {
3384a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        for (int i = 0; i < size; i++) {
339163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
340163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                    && Objects.equal(iface, this.iface[i])) {
341163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                return i;
342163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
343163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
344163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        return -1;
345163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
346163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
347163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    /**
348163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * Find first stats index that matches the requested parameters, starting
349163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * search around the hinted index as an optimization.
350163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     */
3518b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @VisibleForTesting
352163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
353163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        for (int offset = 0; offset < size; offset++) {
354163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int halfOffset = offset / 2;
355163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
356163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            // search outwards from hint index, alternating forward and backward
357163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            final int i;
358163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (offset % 2 == 0) {
359163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                i = (hintIndex + halfOffset) % size;
360163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            } else {
361163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                i = (size + hintIndex - halfOffset - 1) % size;
362163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
363163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
364163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
365163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                    && Objects.equal(iface, this.iface[i])) {
3669a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey                return i;
3679a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            }
3689a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
3699a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return -1;
3709a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
3719a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
372eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    /**
373a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Splice in {@link #operations} from the given {@link NetworkStats} based
374a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
375a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * since operation counts are at data layer.
376a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
377a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void spliceOperationsFrom(NetworkStats stats) {
378a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        for (int i = 0; i < size; i++) {
37921a547823de52806de48f70b8360353344a5ad88Jeff Sharkey            final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]);
380a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (j == -1) {
381a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = 0;
382a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            } else {
383a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = stats.operations[j];
384a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
385a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
386a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
387a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
388a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
38975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Return list of unique interfaces known by this data structure.
39075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
39161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public String[] getUniqueIfaces() {
39275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final HashSet<String> ifaces = new HashSet<String>();
39375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (String iface : this.iface) {
39475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (iface != IFACE_ALL) {
39575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                ifaces.add(iface);
39675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
39775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
39875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return ifaces.toArray(new String[ifaces.size()]);
39975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
40075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
40175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
40261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * Return list of unique UIDs known by this data structure.
40361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
40461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public int[] getUniqueUids() {
40561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final SparseBooleanArray uids = new SparseBooleanArray();
40661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int uid : this.uid) {
40761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            uids.put(uid, true);
40861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
40961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
41061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int size = uids.size();
41161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int[] result = new int[size];
41261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int i = 0; i < size; i++) {
41361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            result[i] = uids.keyAt(i);
41461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
41561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return result;
41661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
41761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
41861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
4198e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * Return total bytes represented by this snapshot object, usually used when
4208e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
4218e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     */
4228e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    public long getTotalBytes() {
42307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = getTotal(null);
42407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry.rxBytes + entry.txBytes;
42507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    }
42607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
42707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    /**
42807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     * Return total of all fields represented by this snapshot object.
42907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     */
43007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    public Entry getTotal(Entry recycle) {
43163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, null, UID_ALL, false);
4321059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4331059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4341059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4351059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4361059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #uid}.
4371059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4381059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public Entry getTotal(Entry recycle, int limitUid) {
43963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, null, limitUid, false);
4401059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4411059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4421059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4431059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4441059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #iface}.
4451059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
4461059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
44763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, limitIface, UID_ALL, false);
44863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
44963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
45063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public Entry getTotalIncludingTags(Entry recycle) {
45163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return getTotal(recycle, null, UID_ALL, true);
4521059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
4531059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4541059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
4551059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total of all fields represented by this snapshot object matching
4561059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * the requested {@link #iface} and {@link #uid}.
4571059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     *
4581059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * @param limitIface Set of {@link #iface} to include in total; or {@code
4591059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     *            null} to include all ifaces.
4601059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
46163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private Entry getTotal(
46263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
46307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
46407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
46507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.iface = IFACE_ALL;
4661059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.uid = limitUid;
46707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.set = SET_ALL;
46807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.tag = TAG_NONE;
46907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxBytes = 0;
47007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxPackets = 0;
47107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txBytes = 0;
47207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txPackets = 0;
4731059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.operations = 0;
47407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
4758e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        for (int i = 0; i < size; i++) {
4761059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
4771059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
4781059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4791059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            if (matchesUid && matchesIface) {
4801059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                // skip specific tags, since already counted in TAG_NONE
48163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                if (tag[i] != TAG_NONE && !includeTags) continue;
4821059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
4831059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.rxBytes += rxBytes[i];
4841059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.rxPackets += rxPackets[i];
4851059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.txBytes += txBytes[i];
4861059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.txPackets += txPackets[i];
4871059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey                entry.operations += operations[i];
4881059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            }
4898e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        }
49007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry;
4918e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    }
4928e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
4938e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    /**
494eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
495eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
496eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * time, and that none of them have disappeared.
497eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     */
4985a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey    public NetworkStats subtract(NetworkStats right) {
49963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return subtract(this, right, null, null);
500d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    }
501d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey
502d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey    /**
5035a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * Subtract the two given {@link NetworkStats} objects, returning the delta
504d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
505d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     * time, and that none of them have disappeared.
5065a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * <p>
5075a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * If counters have rolled backwards, they are clamped to {@code 0} and
5085a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey     * reported to the given {@link NonMonotonicObserver}.
509d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey     */
51063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public static <C> NetworkStats subtract(
51163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) {
5125a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
513163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        if (deltaRealtime < 0) {
5145a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            if (observer != null) {
51563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                observer.foundNonMonotonic(left, -1, right, -1, cookie);
5165a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            }
5175a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            deltaRealtime = 0;
51875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
519eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
52075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // result will have our rows, and elapsed time between snapshots
521fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = new Entry();
5225a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        final NetworkStats result = new NetworkStats(deltaRealtime, left.size);
5235a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        for (int i = 0; i < left.size; i++) {
5245a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.iface = left.iface[i];
5255a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.uid = left.uid[i];
5265a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.set = left.set[i];
5275a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            entry.tag = left.tag[i];
528eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
529eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            // find remote row that matches, and subtract
5305a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey            final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
531eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            if (j == -1) {
532eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // newly appearing row, return entire value
5335a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxBytes = left.rxBytes[i];
5345a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxPackets = left.rxPackets[i];
5355a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txBytes = left.txBytes[i];
5365a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txPackets = left.txPackets[i];
5375a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.operations = left.operations[i];
538eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            } else {
539eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // existing row, subtract remote value
5405a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxBytes = left.rxBytes[i] - right.rxBytes[j];
5415a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.rxPackets = left.rxPackets[i] - right.rxPackets[j];
5425a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txBytes = left.txBytes[i] - right.txBytes[j];
5435a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.txPackets = left.txPackets[i] - right.txPackets[j];
5445a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                entry.operations = left.operations[i] - right.operations[j];
545163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
546163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
547163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                        || entry.txPackets < 0 || entry.operations < 0) {
5485a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    if (observer != null) {
54963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                        observer.foundNonMonotonic(left, i, right, j, cookie);
550d4ef8c8fc9ea70448e5d8138bf8bc96f4e69903fJeff Sharkey                    }
5515a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.rxBytes = Math.max(entry.rxBytes, 0);
5525a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.rxPackets = Math.max(entry.rxPackets, 0);
5535a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.txBytes = Math.max(entry.txBytes, 0);
5545a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.txPackets = Math.max(entry.txPackets, 0);
5555a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey                    entry.operations = Math.max(entry.operations, 0);
5563f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey                }
557eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            }
558fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
559fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            result.addValues(entry);
560eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        }
561eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
5624a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return result;
5639a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
5649a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
565905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
566905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Return total statistics grouped by {@link #iface}; doesn't mutate the
567905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * original structure.
568905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
569905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public NetworkStats groupedByIface() {
570905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
571905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
572905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final Entry entry = new Entry();
573905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.uid = UID_ALL;
574905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.set = SET_ALL;
575905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.tag = TAG_NONE;
576905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.operations = 0L;
577905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
578905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < size; i++) {
579905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
580905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            if (tag[i] != TAG_NONE) continue;
581905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
582905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.iface = iface[i];
583905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxBytes = rxBytes[i];
584905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxPackets = rxPackets[i];
585905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txBytes = txBytes[i];
586905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txPackets = txPackets[i];
587905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            stats.combineValues(entry);
588905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
589905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
590905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        return stats;
591905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
592905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
5931059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    /**
5941059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * Return total statistics grouped by {@link #uid}; doesn't mutate the
5951059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     * original structure.
5961059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey     */
5971059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    public NetworkStats groupedByUid() {
5981059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
5991059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
6001059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        final Entry entry = new Entry();
6011059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.iface = IFACE_ALL;
6021059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.set = SET_ALL;
6031059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        entry.tag = TAG_NONE;
6041059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
6051059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        for (int i = 0; i < size; i++) {
6061059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
6071059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            if (tag[i] != TAG_NONE) continue;
6081059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
6091059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.uid = uid[i];
6101059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.rxBytes = rxBytes[i];
6111059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.rxPackets = rxPackets[i];
6121059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.txBytes = txBytes[i];
6131059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.txPackets = txPackets[i];
6141059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            entry.operations = operations[i];
6151059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey            stats.combineValues(entry);
6161059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        }
6171059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
6181059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey        return stats;
6191059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey    }
6201059c3c30ad96a15695c1a92ae8896e078a6309fJeff Sharkey
621163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    /**
622163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * Return all rows except those attributed to the requested UID; doesn't
623163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     * mutate the original structure.
624163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey     */
625daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey    public NetworkStats withoutUids(int[] uids) {
626163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
627163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
628163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        Entry entry = new Entry();
629163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        for (int i = 0; i < size; i++) {
630163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            entry = getValues(i, entry);
631daa57e8d1866fe4579c280c41604f3660db7cd01Jeff Sharkey            if (!ArrayUtils.contains(uids, entry.uid)) {
632163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey                stats.addValues(entry);
633163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey            }
634163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        }
635163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
636163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey        return stats;
637163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
638163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
6399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public void dump(String prefix, PrintWriter pw) {
6409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print(prefix);
6419a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
642fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        for (int i = 0; i < size; i++) {
6439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(prefix);
6443359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            pw.print("  ["); pw.print(i); pw.print("]");
6453359aca7655a7d18615c1ada6cbabeff403947d1Jeff Sharkey            pw.print(" iface="); pw.print(iface[i]);
6469a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(" uid="); pw.print(uid[i]);
647b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" set="); pw.print(setToString(set[i]));
648b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" tag="); pw.print(tagToString(tag[i]));
649d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" rxBytes="); pw.print(rxBytes[i]);
650fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            pw.print(" rxPackets="); pw.print(rxPackets[i]);
651d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" txBytes="); pw.print(txBytes[i]);
652a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" txPackets="); pw.print(txPackets[i]);
653a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" operations="); pw.println(operations[i]);
6549a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6559a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
6569a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
657b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
658b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #set} value.
659b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
660b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String setToString(int set) {
661b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        switch (set) {
662b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_ALL:
663b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "ALL";
664b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_DEFAULT:
665b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "DEFAULT";
666b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_FOREGROUND:
667b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "FOREGROUND";
668b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            default:
669b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "UNKNOWN";
670b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
671b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
672b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
673b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
674b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #tag} value.
675b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
676b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String tagToString(int tag) {
677b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return "0x" + Integer.toHexString(tag);
678b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
679b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
6809a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    @Override
6819a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public String toString() {
6829a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
6839a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        dump("", new PrintWriter(writer));
6849a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return writer.toString();
6859a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
6869a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
687bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
688eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    public int describeContents() {
689eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        return 0;
690eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
691eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
6929a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
693bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
6949a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats createFromParcel(Parcel in) {
6959a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats(in);
6969a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
6979a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
698bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
6999a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats[] newArray(int size) {
7009a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats[size];
7019a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
7029a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    };
703163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey
70463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public interface NonMonotonicObserver<C> {
7055a7bcf31a44d9875ca5fc010dc213aa2bd5b1168Jeff Sharkey        public void foundNonMonotonic(
70663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
707163e6443f27884a9bfcb9a48ef606dc635852c23Jeff Sharkey    }
7089a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey}
709