NetworkStats.java revision 905b5891d2aa802f447ac2ce5d77b6c5ba06277a
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;
2247eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkeyimport android.util.Log;
2361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport android.util.SparseBooleanArray;
249a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
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 {
4247eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey    private static final String TAG = "NetworkStats";
4347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #iface} value when interface details unavailable. */
459a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final String IFACE_ALL = null;
4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /** {@link #uid} value when UID details unavailable. */
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final int UID_ALL = -1;
48b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value when all sets combined. */
49b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_ALL = -1;
50b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where background data is accounted. */
51b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_DEFAULT = 0;
52b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #set} value where foreground data is accounted. */
53b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static final int SET_FOREGROUND = 1;
54b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /** {@link #tag} value for total data across all tags. */
551b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    public static final int TAG_NONE = 0;
56eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff 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
106b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        @Override
107b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        public String toString() {
108b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            final StringBuilder builder = new StringBuilder();
109b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append("iface=").append(iface);
110b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" uid=").append(uid);
111b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" set=").append(setToString(set));
112b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" tag=").append(tagToString(tag));
113b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxBytes=").append(rxBytes);
114b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" rxPackets=").append(rxPackets);
115b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txBytes=").append(txBytes);
116b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" txPackets=").append(txPackets);
117b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            builder.append(" operations=").append(operations);
118b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey            return builder.toString();
119b3d5957604f8fcaafe72bd76052bc76b682bf443Jeff Sharkey        }
120fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
1219a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1224a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStats(long elapsedRealtime, int initialSize) {
1239a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        this.elapsedRealtime = elapsedRealtime;
1244a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.size = 0;
1254a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.iface = new String[initialSize];
1264a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        this.uid = new int[initialSize];
127b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        this.set = new int[initialSize];
1281b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        this.tag = new int[initialSize];
129d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.rxBytes = new long[initialSize];
130fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.rxPackets = new long[initialSize];
131d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        this.txBytes = new long[initialSize];
132fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        this.txPackets = new long[initialSize];
13363d27a9233fed934340231f438493746084a681dJeff Sharkey        this.operations = new long[initialSize];
1349a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1359a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
1369a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public NetworkStats(Parcel parcel) {
1379a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        elapsedRealtime = parcel.readLong();
1384a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size = parcel.readInt();
1399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        iface = parcel.createStringArray();
1409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        uid = parcel.createIntArray();
141b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set = parcel.createIntArray();
1421b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        tag = parcel.createIntArray();
143d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes = parcel.createLongArray();
144fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets = parcel.createLongArray();
145d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes = parcel.createLongArray();
146fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets = parcel.createLongArray();
14763d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = parcel.createLongArray();
148a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
149a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
150a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /** {@inheritDoc} */
151a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void writeToParcel(Parcel dest, int flags) {
152a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLong(elapsedRealtime);
153a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeInt(size);
154a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeStringArray(iface);
155a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(uid);
156b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        dest.writeIntArray(set);
157a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeIntArray(tag);
158a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxBytes);
159a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(rxPackets);
160a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txBytes);
161a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        dest.writeLongArray(txPackets);
16263d27a9233fed934340231f438493746084a681dJeff Sharkey        dest.writeLongArray(operations);
1639a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
1649a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
165b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    // @VisibleForTesting
166b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addIfaceValues(
167b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
168b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(
169b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
170a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
171a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
172b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    // @VisibleForTesting
173b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
174b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
175b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return addValues(new Entry(
176b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
177fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
178fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
179fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
180fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
181fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * object can be recycled across multiple calls.
182fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
183fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public NetworkStats addValues(Entry entry) {
1844a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (size >= this.iface.length) {
185fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            final int newLength = Math.max(iface.length, 10) * 3 / 2;
186fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            iface = Arrays.copyOf(iface, newLength);
187fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            uid = Arrays.copyOf(uid, newLength);
188b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            set = Arrays.copyOf(set, newLength);
189fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            tag = Arrays.copyOf(tag, newLength);
190d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes = Arrays.copyOf(rxBytes, newLength);
191fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            rxPackets = Arrays.copyOf(rxPackets, newLength);
192d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes = Arrays.copyOf(txBytes, newLength);
193fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            txPackets = Arrays.copyOf(txPackets, newLength);
194a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations = Arrays.copyOf(operations, newLength);
1959a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
1969a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
197fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        iface[size] = entry.iface;
198fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        uid[size] = entry.uid;
199b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        set[size] = entry.set;
200fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        tag[size] = entry.tag;
201d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        rxBytes[size] = entry.rxBytes;
202fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        rxPackets[size] = entry.rxPackets;
203d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        txBytes[size] = entry.txBytes;
204fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        txPackets[size] = entry.txPackets;
205a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        operations[size] = entry.operations;
2064a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        size++;
2079a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2084a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return this;
2099a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
2109a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
2111b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    /**
212fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     * Return specific stats entry.
213fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey     */
214fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public Entry getValues(int i, Entry recycle) {
215fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
216fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.iface = iface[i];
217fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.uid = uid[i];
218b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        entry.set = set[i];
219fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.tag = tag[i];
220d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.rxBytes = rxBytes[i];
221fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.rxPackets = rxPackets[i];
222d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.txBytes = txBytes[i];
223fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        entry.txPackets = txPackets[i];
224a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        entry.operations = operations[i];
225fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return entry;
226fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
227fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
228fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public long getElapsedRealtime() {
229fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return elapsedRealtime;
230fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
231fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
232fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    public int size() {
233fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        return size;
234fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    }
235fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
236d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    // @VisibleForTesting
237d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int internalSize() {
238d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return iface.length;
239d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
240d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
241b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    @Deprecated
242d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
24363d27a9233fed934340231f438493746084a681dJeff Sharkey            long txBytes, long txPackets, long operations) {
244a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        return combineValues(
245b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
246b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
247b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
248b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
249b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            long rxPackets, long txBytes, long txPackets, long operations) {
250b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return combineValues(new Entry(
251b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
252d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
253d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
254fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey    /**
2551b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     * Combine given values with an existing row, or create a new row if
256b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * {@link #findIndex(String, int, int, int)} is unable to find match. Can
257b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * also be used to subtract values from existing rows.
2581b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey     */
259d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public NetworkStats combineValues(Entry entry) {
260b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
2611b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        if (i == -1) {
2621b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            // only create new entry when positive contribution
263d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            addValues(entry);
2641b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        } else {
265d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxBytes[i] += entry.rxBytes;
266d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            rxPackets[i] += entry.rxPackets;
267d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txBytes[i] += entry.txBytes;
268d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            txPackets[i] += entry.txPackets;
269a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            operations[i] += entry.operations;
2701b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
2711b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        return this;
272eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
273eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
2749a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /**
275905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Combine all values from another {@link NetworkStats} into this object.
276905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
277905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public void combineAllValues(NetworkStats another) {
278905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        NetworkStats.Entry entry = null;
279905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < another.size; i++) {
280905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry = another.getValues(i, entry);
281905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            combineValues(entry);
282905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
283905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
284905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
285905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
2869a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     * Find first stats index that matches the requested parameters.
2879a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey     */
288b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public int findIndex(String iface, int uid, int set, int tag) {
2894a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        for (int i = 0; i < size; i++) {
290b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && set == this.set[i]
291b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                    && tag == this.tag[i]) {
2929a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey                return i;
2939a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            }
2949a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
2959a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return -1;
2969a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
2979a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
298eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    /**
299a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Splice in {@link #operations} from the given {@link NetworkStats} based
300a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
301a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * since operation counts are at data layer.
302a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
303a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void spliceOperationsFrom(NetworkStats stats) {
304a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        for (int i = 0; i < size; i++) {
305b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
306a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (j == -1) {
307a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = 0;
308a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            } else {
309a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                operations[i] = stats.operations[j];
310a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
311a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
312a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
313a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
314a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Return list of unique interfaces known by this data structure.
31675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
31761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public String[] getUniqueIfaces() {
31875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final HashSet<String> ifaces = new HashSet<String>();
31975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (String iface : this.iface) {
32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (iface != IFACE_ALL) {
32175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                ifaces.add(iface);
32275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
32375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
32475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return ifaces.toArray(new String[ifaces.size()]);
32575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
32675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
32775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
32861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * Return list of unique UIDs known by this data structure.
32961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
33061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    public int[] getUniqueUids() {
33161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final SparseBooleanArray uids = new SparseBooleanArray();
33261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int uid : this.uid) {
33361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            uids.put(uid, true);
33461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
33561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
33661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int size = uids.size();
33761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        final int[] result = new int[size];
33861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        for (int i = 0; i < size; i++) {
33961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            result[i] = uids.keyAt(i);
34061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
34161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return result;
34261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
34361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
34461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
3458e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * Return total bytes represented by this snapshot object, usually used when
3468e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
3478e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey     */
3488e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    public long getTotalBytes() {
34907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = getTotal(null);
35007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry.rxBytes + entry.txBytes;
35107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    }
35207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
35307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    /**
35407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     * Return total of all fields represented by this snapshot object.
35507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey     */
35607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey    public Entry getTotal(Entry recycle) {
35707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
35807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
35907b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.iface = IFACE_ALL;
36007b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.uid = UID_ALL;
36107b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.set = SET_ALL;
36207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.tag = TAG_NONE;
36307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxBytes = 0;
36407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.rxPackets = 0;
36507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txBytes = 0;
36607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        entry.txPackets = 0;
36707b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey
3688e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        for (int i = 0; i < size; i++) {
3698e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
3708e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey            if (tag[i] != TAG_NONE) continue;
3718e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
37207b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey            entry.rxBytes += rxBytes[i];
37307b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey            entry.rxPackets += rxPackets[i];
37407b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey            entry.txBytes += txBytes[i];
37507b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey            entry.txPackets += txPackets[i];
37607b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey            entry.operations += operations[i];
3778e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey        }
37807b0dd9a092273f0451cd9881312cb9b22a7af3fJeff Sharkey        return entry;
3798e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    }
3808e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey
3818e9992ae5053a3ac52d28a5a892aed0a0798c7abJeff Sharkey    /**
382eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
383eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
384eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     * time, and that none of them have disappeared.
38575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     *
3863f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * @throws IllegalArgumentException when given {@link NetworkStats} is
3873f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     *             non-monotonic.
3883f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     */
3893f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    public NetworkStats subtract(NetworkStats value) {
3903f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey        return subtract(value, true, false);
3913f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    }
3923f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey
3933f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    /**
3943f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
3953f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
3963f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * time, and that none of them have disappeared.
3973f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * <p>
3983f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * Instead of throwing when counters are non-monotonic, this variant clamps
3993f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * results to never be negative.
4003f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     */
4013f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    public NetworkStats subtractClamped(NetworkStats value) {
4023f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey        return subtract(value, false, true);
4033f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    }
4043f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey
4053f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    /**
4063f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * Subtract the given {@link NetworkStats}, effectively leaving the delta
4073f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * between two snapshots in time. Assumes that statistics rows collect over
4083f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * time, and that none of them have disappeared.
4093f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     *
41075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * @param enforceMonotonic Validate that incoming value is strictly
41175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     *            monotonic compared to this object.
4123f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     * @param clampNegative Instead of throwing like {@code enforceMonotonic},
4133f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey     *            clamp resulting counters at 0 to prevent negative values.
414eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey     */
4153f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey    private NetworkStats subtract(
4163f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey            NetworkStats value, boolean enforceMonotonic, boolean clampNegative) {
41775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
41875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (enforceMonotonic && deltaRealtime < 0) {
41975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            throw new IllegalArgumentException("found non-monotonic realtime");
42075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
421eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
42275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // result will have our rows, and elapsed time between snapshots
423fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        final Entry entry = new Entry();
4244a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        final NetworkStats result = new NetworkStats(deltaRealtime, size);
4254a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        for (int i = 0; i < size; i++) {
426fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            entry.iface = iface[i];
427fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            entry.uid = uid[i];
428b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            entry.set = set[i];
429fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            entry.tag = tag[i];
430eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
431eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            // find remote row that matches, and subtract
432b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            final int j = value.findIndex(entry.iface, entry.uid, entry.set, entry.tag);
433eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            if (j == -1) {
434eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // newly appearing row, return entire value
435d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.rxBytes = rxBytes[i];
436fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.rxPackets = rxPackets[i];
437d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.txBytes = txBytes[i];
438fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.txPackets = txPackets[i];
439a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                entry.operations = operations[i];
440eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            } else {
441eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey                // existing row, subtract remote value
442d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.rxBytes = rxBytes[i] - value.rxBytes[j];
443fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.rxPackets = rxPackets[i] - value.rxPackets[j];
444d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey                entry.txBytes = txBytes[i] - value.txBytes[j];
445fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                entry.txPackets = txPackets[i] - value.txPackets[j];
446a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                entry.operations = operations[i] - value.operations[j];
447fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                if (enforceMonotonic
448fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                        && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
449a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                                || entry.txPackets < 0 || entry.operations < 0)) {
45047eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                    Log.v(TAG, "lhs=" + this);
45147eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                    Log.v(TAG, "rhs=" + value);
45247eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                    throw new IllegalArgumentException(
45347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey                            "found non-monotonic values at lhs[" + i + "] - rhs[" + j + "]");
45475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                }
4553f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey                if (clampNegative) {
456fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                    entry.rxBytes = Math.max(0, entry.rxBytes);
457fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                    entry.rxPackets = Math.max(0, entry.rxPackets);
458fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                    entry.txBytes = Math.max(0, entry.txBytes);
459fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey                    entry.txPackets = Math.max(0, entry.txPackets);
460a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                    entry.operations = Math.max(0, entry.operations);
4613f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey                }
462eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey            }
463fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey
464fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            result.addValues(entry);
465eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        }
466eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
4674a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        return result;
4689a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
4699a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
470905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    /**
471905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * Return total statistics grouped by {@link #iface}; doesn't mutate the
472905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     * original structure.
473905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey     */
474905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    public NetworkStats groupedByIface() {
475905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
476905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
477905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        final Entry entry = new Entry();
478905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.uid = UID_ALL;
479905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.set = SET_ALL;
480905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.tag = TAG_NONE;
481905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        entry.operations = 0L;
482905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
483905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        for (int i = 0; i < size; i++) {
484905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            // skip specific tags, since already counted in TAG_NONE
485905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            if (tag[i] != TAG_NONE) continue;
486905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
487905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.iface = iface[i];
488905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxBytes = rxBytes[i];
489905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.rxPackets = rxPackets[i];
490905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txBytes = txBytes[i];
491905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            entry.txPackets = txPackets[i];
492905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey            stats.combineValues(entry);
493905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        }
494905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
495905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey        return stats;
496905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey    }
497905b5891d2aa802f447ac2ce5d77b6c5ba06277aJeff Sharkey
4989a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public void dump(String prefix, PrintWriter pw) {
4999a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print(prefix);
5009a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
501fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey        for (int i = 0; i < size; i++) {
5029a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(prefix);
5039a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print("  iface="); pw.print(iface[i]);
5049a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            pw.print(" uid="); pw.print(uid[i]);
505b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" set="); pw.print(setToString(set[i]));
506b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            pw.print(" tag="); pw.print(tagToString(tag[i]));
507d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" rxBytes="); pw.print(rxBytes[i]);
508fd8be3e5e7420f3cca591daeec8a44487f5f65aaJeff Sharkey            pw.print(" rxPackets="); pw.print(rxPackets[i]);
509d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey            pw.print(" txBytes="); pw.print(txBytes[i]);
510a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" txPackets="); pw.print(txPackets[i]);
511a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            pw.print(" operations="); pw.println(operations[i]);
5129a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
5139a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
5149a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
515b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
516b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #set} value.
517b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
518b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String setToString(int set) {
519b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        switch (set) {
520b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_ALL:
521b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "ALL";
522b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_DEFAULT:
523b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "DEFAULT";
524b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            case SET_FOREGROUND:
525b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "FOREGROUND";
526b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey            default:
527b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                return "UNKNOWN";
528b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
529b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
530b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
531b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    /**
532b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     * Return text description of {@link #tag} value.
533b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey     */
534b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static String tagToString(int tag) {
535b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        return "0x" + Integer.toHexString(tag);
536b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
537b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
5389a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    @Override
5399a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public String toString() {
5409a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
5419a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        dump("", new PrintWriter(writer));
5429a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        return writer.toString();
5439a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    }
5449a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
5459a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    /** {@inheritDoc} */
546eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    public int describeContents() {
547eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey        return 0;
548eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey    }
549eedcb9525ba5befee2ba6ebb7a9ee3f13395c2a3Jeff Sharkey
5509a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
5519a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats createFromParcel(Parcel in) {
5529a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats(in);
5539a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
5549a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey
5559a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        public NetworkStats[] newArray(int size) {
5569a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey            return new NetworkStats[size];
5579a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey        }
5589a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey    };
5599a13f36cddaad01350bdb5f000167811a1d753c9Jeff Sharkey}
560