blob: 25514f4c25ac63379d88e54acf3e22b6a892a9dd [file] [log] [blame]
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.os.SystemClock;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070022import android.util.SparseBooleanArray;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070023
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080024import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070025import com.android.internal.util.ArrayUtils;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070026
Jeff Sharkey9a13f362011-04-26 16:25:36 -070027import java.io.CharArrayWriter;
28import java.io.PrintWriter;
Jeff Sharkey4a971222011-06-11 22:16:55 -070029import java.util.Arrays;
Jeff Sharkey75279902011-05-24 18:39:45 -070030import java.util.HashSet;
Kenny Roote6585b32013-12-13 12:00:26 -080031import java.util.Objects;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070032
33/**
Jeff Sharkey75279902011-05-24 18:39:45 -070034 * Collection of active network statistics. Can contain summary details across
35 * all interfaces, or details with per-UID granularity. Internally stores data
36 * as a large table, closely matching {@code /proc/} data format. This structure
37 * optimizes for rapid in-memory comparison, but consider using
38 * {@link NetworkStatsHistory} when persisting.
Jeff Sharkey9a13f362011-04-26 16:25:36 -070039 *
40 * @hide
41 */
42public class NetworkStats implements Parcelable {
Jeff Sharkey75279902011-05-24 18:39:45 -070043 /** {@link #iface} value when interface details unavailable. */
Jeff Sharkey9a13f362011-04-26 16:25:36 -070044 public static final String IFACE_ALL = null;
Jeff Sharkey75279902011-05-24 18:39:45 -070045 /** {@link #uid} value when UID details unavailable. */
46 public static final int UID_ALL = -1;
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -080047 /** {@link #tag} value matching any tag. */
48 public static final int TAG_ALL = -1;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070049 /** {@link #set} value when all sets combined. */
50 public static final int SET_ALL = -1;
51 /** {@link #set} value where background data is accounted. */
52 public static final int SET_DEFAULT = 0;
53 /** {@link #set} value where foreground data is accounted. */
54 public static final int SET_FOREGROUND = 1;
55 /** {@link #tag} value for total data across all tags. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070056 public static final int TAG_NONE = 0;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070057
Jeff Sharkey163e6442011-10-31 16:37:52 -070058 // TODO: move fields to "mVariable" notation
59
Jeff Sharkey9a13f362011-04-26 16:25:36 -070060 /**
61 * {@link SystemClock#elapsedRealtime()} timestamp when this data was
62 * generated.
63 */
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -080064 private long elapsedRealtime;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070065 private int size;
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -080066 private int capacity;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070067 private String[] iface;
68 private int[] uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070069 private int[] set;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070070 private int[] tag;
71 private long[] rxBytes;
72 private long[] rxPackets;
73 private long[] txBytes;
74 private long[] txPackets;
Jeff Sharkey63d27a92011-08-03 17:04:22 -070075 private long[] operations;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070076
77 public static class Entry {
78 public String iface;
79 public int uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070080 public int set;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070081 public int tag;
82 public long rxBytes;
83 public long rxPackets;
84 public long txBytes;
85 public long txPackets;
Jeff Sharkey63d27a92011-08-03 17:04:22 -070086 public long operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070087
88 public Entry() {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070089 this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
Jeff Sharkey63d27a92011-08-03 17:04:22 -070090 }
91
92 public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070093 this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
94 operations);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070095 }
96
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070097 public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
98 long txBytes, long txPackets, long operations) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070099 this.iface = iface;
100 this.uid = uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700101 this.set = set;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700102 this.tag = tag;
103 this.rxBytes = rxBytes;
104 this.rxPackets = rxPackets;
105 this.txBytes = txBytes;
106 this.txPackets = txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700107 this.operations = operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700108 }
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700109
Jeff Sharkey63abc372012-01-11 18:38:16 -0800110 public boolean isNegative() {
111 return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
112 }
113
114 public boolean isEmpty() {
115 return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
116 && operations == 0;
117 }
118
Jeff Sharkey70c70532012-05-16 14:51:19 -0700119 public void add(Entry another) {
120 this.rxBytes += another.rxBytes;
121 this.rxPackets += another.rxPackets;
122 this.txBytes += another.txBytes;
123 this.txPackets += another.txPackets;
124 this.operations += another.operations;
125 }
126
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700127 @Override
128 public String toString() {
129 final StringBuilder builder = new StringBuilder();
130 builder.append("iface=").append(iface);
131 builder.append(" uid=").append(uid);
132 builder.append(" set=").append(setToString(set));
133 builder.append(" tag=").append(tagToString(tag));
134 builder.append(" rxBytes=").append(rxBytes);
135 builder.append(" rxPackets=").append(rxPackets);
136 builder.append(" txBytes=").append(txBytes);
137 builder.append(" txPackets=").append(txPackets);
138 builder.append(" operations=").append(operations);
139 return builder.toString();
140 }
Jeff Sharkey9a2c2a62013-01-14 16:48:51 -0800141
142 @Override
143 public boolean equals(Object o) {
144 if (o instanceof Entry) {
145 final Entry e = (Entry) o;
146 return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes
147 && rxPackets == e.rxPackets && txBytes == e.txBytes
148 && txPackets == e.txPackets && operations == e.operations
149 && iface.equals(e.iface);
150 }
151 return false;
152 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700153 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700154
Jeff Sharkey4a971222011-06-11 22:16:55 -0700155 public NetworkStats(long elapsedRealtime, int initialSize) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700156 this.elapsedRealtime = elapsedRealtime;
Jeff Sharkey4a971222011-06-11 22:16:55 -0700157 this.size = 0;
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800158 if (initialSize >= 0) {
159 this.capacity = initialSize;
160 this.iface = new String[initialSize];
161 this.uid = new int[initialSize];
162 this.set = new int[initialSize];
163 this.tag = new int[initialSize];
164 this.rxBytes = new long[initialSize];
165 this.rxPackets = new long[initialSize];
166 this.txBytes = new long[initialSize];
167 this.txPackets = new long[initialSize];
168 this.operations = new long[initialSize];
169 } else {
170 // Special case for use by NetworkStatsFactory to start out *really* empty.
171 this.capacity = 0;
172 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700173 }
174
175 public NetworkStats(Parcel parcel) {
176 elapsedRealtime = parcel.readLong();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700177 size = parcel.readInt();
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800178 capacity = parcel.readInt();
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700179 iface = parcel.createStringArray();
180 uid = parcel.createIntArray();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700181 set = parcel.createIntArray();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700182 tag = parcel.createIntArray();
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700183 rxBytes = parcel.createLongArray();
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700184 rxPackets = parcel.createLongArray();
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700185 txBytes = parcel.createLongArray();
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700186 txPackets = parcel.createLongArray();
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700187 operations = parcel.createLongArray();
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700188 }
189
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700190 @Override
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700191 public void writeToParcel(Parcel dest, int flags) {
192 dest.writeLong(elapsedRealtime);
193 dest.writeInt(size);
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800194 dest.writeInt(capacity);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700195 dest.writeStringArray(iface);
196 dest.writeIntArray(uid);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700197 dest.writeIntArray(set);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700198 dest.writeIntArray(tag);
199 dest.writeLongArray(rxBytes);
200 dest.writeLongArray(rxPackets);
201 dest.writeLongArray(txBytes);
202 dest.writeLongArray(txPackets);
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700203 dest.writeLongArray(operations);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700204 }
205
Jeff Sharkey4abb1b82011-11-08 17:35:28 -0800206 @Override
207 public NetworkStats clone() {
208 final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
209 NetworkStats.Entry entry = null;
210 for (int i = 0; i < size; i++) {
211 entry = getValues(i, entry);
212 clone.addValues(entry);
213 }
214 return clone;
215 }
216
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800217 @VisibleForTesting
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700218 public NetworkStats addIfaceValues(
219 String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
220 return addValues(
221 iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700222 }
223
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800224 @VisibleForTesting
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700225 public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
226 long rxPackets, long txBytes, long txPackets, long operations) {
227 return addValues(new Entry(
228 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700229 }
230
231 /**
232 * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
233 * object can be recycled across multiple calls.
234 */
235 public NetworkStats addValues(Entry entry) {
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800236 if (size >= capacity) {
237 final int newLength = Math.max(size, 10) * 3 / 2;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700238 iface = Arrays.copyOf(iface, newLength);
239 uid = Arrays.copyOf(uid, newLength);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700240 set = Arrays.copyOf(set, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700241 tag = Arrays.copyOf(tag, newLength);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700242 rxBytes = Arrays.copyOf(rxBytes, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700243 rxPackets = Arrays.copyOf(rxPackets, newLength);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700244 txBytes = Arrays.copyOf(txBytes, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700245 txPackets = Arrays.copyOf(txPackets, newLength);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700246 operations = Arrays.copyOf(operations, newLength);
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800247 capacity = newLength;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700248 }
249
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700250 iface[size] = entry.iface;
251 uid[size] = entry.uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700252 set[size] = entry.set;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700253 tag[size] = entry.tag;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700254 rxBytes[size] = entry.rxBytes;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700255 rxPackets[size] = entry.rxPackets;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700256 txBytes[size] = entry.txBytes;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700257 txPackets[size] = entry.txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700258 operations[size] = entry.operations;
Jeff Sharkey4a971222011-06-11 22:16:55 -0700259 size++;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700260
Jeff Sharkey4a971222011-06-11 22:16:55 -0700261 return this;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700262 }
263
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700264 /**
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700265 * Return specific stats entry.
266 */
267 public Entry getValues(int i, Entry recycle) {
268 final Entry entry = recycle != null ? recycle : new Entry();
269 entry.iface = iface[i];
270 entry.uid = uid[i];
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700271 entry.set = set[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700272 entry.tag = tag[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700273 entry.rxBytes = rxBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700274 entry.rxPackets = rxPackets[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700275 entry.txBytes = txBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700276 entry.txPackets = txPackets[i];
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700277 entry.operations = operations[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700278 return entry;
279 }
280
281 public long getElapsedRealtime() {
282 return elapsedRealtime;
283 }
284
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800285 public void setElapsedRealtime(long time) {
286 elapsedRealtime = time;
287 }
288
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700289 /**
290 * Return age of this {@link NetworkStats} object with respect to
291 * {@link SystemClock#elapsedRealtime()}.
292 */
293 public long getElapsedRealtimeAge() {
294 return SystemClock.elapsedRealtime() - elapsedRealtime;
295 }
296
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700297 public int size() {
298 return size;
299 }
300
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800301 @VisibleForTesting
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700302 public int internalSize() {
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800303 return capacity;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700304 }
305
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700306 @Deprecated
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700307 public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700308 long txBytes, long txPackets, long operations) {
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700309 return combineValues(
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700310 iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
311 }
312
313 public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
314 long rxPackets, long txBytes, long txPackets, long operations) {
315 return combineValues(new Entry(
316 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700317 }
318
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700319 /**
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700320 * Combine given values with an existing row, or create a new row if
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700321 * {@link #findIndex(String, int, int, int)} is unable to find match. Can
322 * also be used to subtract values from existing rows.
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700323 */
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700324 public NetworkStats combineValues(Entry entry) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700325 final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700326 if (i == -1) {
327 // only create new entry when positive contribution
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700328 addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700329 } else {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700330 rxBytes[i] += entry.rxBytes;
331 rxPackets[i] += entry.rxPackets;
332 txBytes[i] += entry.txBytes;
333 txPackets[i] += entry.txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700334 operations[i] += entry.operations;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700335 }
336 return this;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700337 }
338
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700339 /**
Jeff Sharkey905b5892011-09-30 15:19:49 -0700340 * Combine all values from another {@link NetworkStats} into this object.
341 */
342 public void combineAllValues(NetworkStats another) {
343 NetworkStats.Entry entry = null;
344 for (int i = 0; i < another.size; i++) {
345 entry = another.getValues(i, entry);
346 combineValues(entry);
347 }
348 }
349
350 /**
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700351 * Find first stats index that matches the requested parameters.
352 */
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700353 public int findIndex(String iface, int uid, int set, int tag) {
Jeff Sharkey4a971222011-06-11 22:16:55 -0700354 for (int i = 0; i < size; i++) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700355 if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
Kenny Roote6585b32013-12-13 12:00:26 -0800356 && Objects.equals(iface, this.iface[i])) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700357 return i;
358 }
359 }
360 return -1;
361 }
362
363 /**
364 * Find first stats index that matches the requested parameters, starting
365 * search around the hinted index as an optimization.
366 */
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800367 @VisibleForTesting
Jeff Sharkey163e6442011-10-31 16:37:52 -0700368 public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
369 for (int offset = 0; offset < size; offset++) {
370 final int halfOffset = offset / 2;
371
372 // search outwards from hint index, alternating forward and backward
373 final int i;
374 if (offset % 2 == 0) {
375 i = (hintIndex + halfOffset) % size;
376 } else {
377 i = (size + hintIndex - halfOffset - 1) % size;
378 }
379
380 if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
Kenny Roote6585b32013-12-13 12:00:26 -0800381 && Objects.equals(iface, this.iface[i])) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700382 return i;
383 }
384 }
385 return -1;
386 }
387
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700388 /**
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700389 * Splice in {@link #operations} from the given {@link NetworkStats} based
390 * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
391 * since operation counts are at data layer.
392 */
393 public void spliceOperationsFrom(NetworkStats stats) {
394 for (int i = 0; i < size; i++) {
Jeff Sharkey21a54782012-04-09 10:27:55 -0700395 final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700396 if (j == -1) {
397 operations[i] = 0;
398 } else {
399 operations[i] = stats.operations[j];
400 }
401 }
402 }
403
404 /**
Jeff Sharkey75279902011-05-24 18:39:45 -0700405 * Return list of unique interfaces known by this data structure.
406 */
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700407 public String[] getUniqueIfaces() {
Jeff Sharkey75279902011-05-24 18:39:45 -0700408 final HashSet<String> ifaces = new HashSet<String>();
409 for (String iface : this.iface) {
410 if (iface != IFACE_ALL) {
411 ifaces.add(iface);
412 }
413 }
414 return ifaces.toArray(new String[ifaces.size()]);
415 }
416
417 /**
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700418 * Return list of unique UIDs known by this data structure.
419 */
420 public int[] getUniqueUids() {
421 final SparseBooleanArray uids = new SparseBooleanArray();
422 for (int uid : this.uid) {
423 uids.put(uid, true);
424 }
425
426 final int size = uids.size();
427 final int[] result = new int[size];
428 for (int i = 0; i < size; i++) {
429 result[i] = uids.keyAt(i);
430 }
431 return result;
432 }
433
434 /**
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700435 * Return total bytes represented by this snapshot object, usually used when
436 * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
437 */
438 public long getTotalBytes() {
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700439 final Entry entry = getTotal(null);
440 return entry.rxBytes + entry.txBytes;
441 }
442
443 /**
444 * Return total of all fields represented by this snapshot object.
445 */
446 public Entry getTotal(Entry recycle) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800447 return getTotal(recycle, null, UID_ALL, false);
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700448 }
449
450 /**
451 * Return total of all fields represented by this snapshot object matching
452 * the requested {@link #uid}.
453 */
454 public Entry getTotal(Entry recycle, int limitUid) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800455 return getTotal(recycle, null, limitUid, false);
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700456 }
457
458 /**
459 * Return total of all fields represented by this snapshot object matching
460 * the requested {@link #iface}.
461 */
462 public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800463 return getTotal(recycle, limitIface, UID_ALL, false);
464 }
465
466 public Entry getTotalIncludingTags(Entry recycle) {
467 return getTotal(recycle, null, UID_ALL, true);
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700468 }
469
470 /**
471 * Return total of all fields represented by this snapshot object matching
472 * the requested {@link #iface} and {@link #uid}.
473 *
474 * @param limitIface Set of {@link #iface} to include in total; or {@code
475 * null} to include all ifaces.
476 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800477 private Entry getTotal(
478 Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700479 final Entry entry = recycle != null ? recycle : new Entry();
480
481 entry.iface = IFACE_ALL;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700482 entry.uid = limitUid;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700483 entry.set = SET_ALL;
484 entry.tag = TAG_NONE;
485 entry.rxBytes = 0;
486 entry.rxPackets = 0;
487 entry.txBytes = 0;
488 entry.txPackets = 0;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700489 entry.operations = 0;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700490
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700491 for (int i = 0; i < size; i++) {
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700492 final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
493 final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700494
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700495 if (matchesUid && matchesIface) {
496 // skip specific tags, since already counted in TAG_NONE
Jeff Sharkey63abc372012-01-11 18:38:16 -0800497 if (tag[i] != TAG_NONE && !includeTags) continue;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700498
499 entry.rxBytes += rxBytes[i];
500 entry.rxPackets += rxPackets[i];
501 entry.txBytes += txBytes[i];
502 entry.txPackets += txPackets[i];
503 entry.operations += operations[i];
504 }
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700505 }
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700506 return entry;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700507 }
508
509 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700510 * Subtract the given {@link NetworkStats}, effectively leaving the delta
511 * between two snapshots in time. Assumes that statistics rows collect over
512 * time, and that none of them have disappeared.
Jeff Sharkey3f391352011-06-05 17:42:53 -0700513 */
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800514 public NetworkStats subtract(NetworkStats right) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800515 return subtract(this, right, null, null);
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800516 }
517
518 /**
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800519 * Subtract the two given {@link NetworkStats} objects, returning the delta
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800520 * between two snapshots in time. Assumes that statistics rows collect over
521 * time, and that none of them have disappeared.
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800522 * <p>
523 * If counters have rolled backwards, they are clamped to {@code 0} and
524 * reported to the given {@link NonMonotonicObserver}.
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800525 */
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800526 public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
527 NonMonotonicObserver<C> observer, C cookie) {
528 return subtract(left, right, observer, cookie, null);
529 }
530
531 /**
532 * Subtract the two given {@link NetworkStats} objects, returning the delta
533 * between two snapshots in time. Assumes that statistics rows collect over
534 * time, and that none of them have disappeared.
535 * <p>
536 * If counters have rolled backwards, they are clamped to {@code 0} and
537 * reported to the given {@link NonMonotonicObserver}.
538 * <p>
539 * If <var>recycle</var> is supplied, this NetworkStats object will be
540 * reused (and returned) as the result if it is large enough to contain
541 * the data.
542 */
543 public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
544 NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800545 long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700546 if (deltaRealtime < 0) {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800547 if (observer != null) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800548 observer.foundNonMonotonic(left, -1, right, -1, cookie);
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800549 }
550 deltaRealtime = 0;
Jeff Sharkey75279902011-05-24 18:39:45 -0700551 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700552
Jeff Sharkey75279902011-05-24 18:39:45 -0700553 // result will have our rows, and elapsed time between snapshots
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700554 final Entry entry = new Entry();
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800555 final NetworkStats result;
556 if (recycle != null && recycle.capacity >= left.size) {
557 result = recycle;
558 result.size = 0;
559 result.elapsedRealtime = deltaRealtime;
560 } else {
561 result = new NetworkStats(deltaRealtime, left.size);
562 }
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800563 for (int i = 0; i < left.size; i++) {
564 entry.iface = left.iface[i];
565 entry.uid = left.uid[i];
566 entry.set = left.set[i];
567 entry.tag = left.tag[i];
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700568
569 // find remote row that matches, and subtract
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800570 final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700571 if (j == -1) {
572 // newly appearing row, return entire value
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800573 entry.rxBytes = left.rxBytes[i];
574 entry.rxPackets = left.rxPackets[i];
575 entry.txBytes = left.txBytes[i];
576 entry.txPackets = left.txPackets[i];
577 entry.operations = left.operations[i];
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700578 } else {
579 // existing row, subtract remote value
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800580 entry.rxBytes = left.rxBytes[i] - right.rxBytes[j];
581 entry.rxPackets = left.rxPackets[i] - right.rxPackets[j];
582 entry.txBytes = left.txBytes[i] - right.txBytes[j];
583 entry.txPackets = left.txPackets[i] - right.txPackets[j];
584 entry.operations = left.operations[i] - right.operations[j];
Jeff Sharkey163e6442011-10-31 16:37:52 -0700585
586 if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
587 || entry.txPackets < 0 || entry.operations < 0) {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800588 if (observer != null) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800589 observer.foundNonMonotonic(left, i, right, j, cookie);
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800590 }
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800591 entry.rxBytes = Math.max(entry.rxBytes, 0);
592 entry.rxPackets = Math.max(entry.rxPackets, 0);
593 entry.txBytes = Math.max(entry.txBytes, 0);
594 entry.txPackets = Math.max(entry.txPackets, 0);
595 entry.operations = Math.max(entry.operations, 0);
Jeff Sharkey3f391352011-06-05 17:42:53 -0700596 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700597 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700598
599 result.addValues(entry);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700600 }
601
Jeff Sharkey4a971222011-06-11 22:16:55 -0700602 return result;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700603 }
604
Jeff Sharkey905b5892011-09-30 15:19:49 -0700605 /**
606 * Return total statistics grouped by {@link #iface}; doesn't mutate the
607 * original structure.
608 */
609 public NetworkStats groupedByIface() {
610 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
611
612 final Entry entry = new Entry();
613 entry.uid = UID_ALL;
614 entry.set = SET_ALL;
615 entry.tag = TAG_NONE;
616 entry.operations = 0L;
617
618 for (int i = 0; i < size; i++) {
619 // skip specific tags, since already counted in TAG_NONE
620 if (tag[i] != TAG_NONE) continue;
621
622 entry.iface = iface[i];
623 entry.rxBytes = rxBytes[i];
624 entry.rxPackets = rxPackets[i];
625 entry.txBytes = txBytes[i];
626 entry.txPackets = txPackets[i];
627 stats.combineValues(entry);
628 }
629
630 return stats;
631 }
632
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700633 /**
634 * Return total statistics grouped by {@link #uid}; doesn't mutate the
635 * original structure.
636 */
637 public NetworkStats groupedByUid() {
638 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
639
640 final Entry entry = new Entry();
641 entry.iface = IFACE_ALL;
642 entry.set = SET_ALL;
643 entry.tag = TAG_NONE;
644
645 for (int i = 0; i < size; i++) {
646 // skip specific tags, since already counted in TAG_NONE
647 if (tag[i] != TAG_NONE) continue;
648
649 entry.uid = uid[i];
650 entry.rxBytes = rxBytes[i];
651 entry.rxPackets = rxPackets[i];
652 entry.txBytes = txBytes[i];
653 entry.txPackets = txPackets[i];
654 entry.operations = operations[i];
655 stats.combineValues(entry);
656 }
657
658 return stats;
659 }
660
Jeff Sharkey163e6442011-10-31 16:37:52 -0700661 /**
662 * Return all rows except those attributed to the requested UID; doesn't
663 * mutate the original structure.
664 */
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700665 public NetworkStats withoutUids(int[] uids) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700666 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
667
668 Entry entry = new Entry();
669 for (int i = 0; i < size; i++) {
670 entry = getValues(i, entry);
Jeff Sharkeydaa57e82012-09-19 14:10:39 -0700671 if (!ArrayUtils.contains(uids, entry.uid)) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700672 stats.addValues(entry);
673 }
674 }
675
676 return stats;
677 }
678
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700679 public void dump(String prefix, PrintWriter pw) {
680 pw.print(prefix);
681 pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700682 for (int i = 0; i < size; i++) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700683 pw.print(prefix);
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800684 pw.print(" ["); pw.print(i); pw.print("]");
685 pw.print(" iface="); pw.print(iface[i]);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700686 pw.print(" uid="); pw.print(uid[i]);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700687 pw.print(" set="); pw.print(setToString(set[i]));
688 pw.print(" tag="); pw.print(tagToString(tag[i]));
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700689 pw.print(" rxBytes="); pw.print(rxBytes[i]);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700690 pw.print(" rxPackets="); pw.print(rxPackets[i]);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700691 pw.print(" txBytes="); pw.print(txBytes[i]);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700692 pw.print(" txPackets="); pw.print(txPackets[i]);
693 pw.print(" operations="); pw.println(operations[i]);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700694 }
695 }
696
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700697 /**
698 * Return text description of {@link #set} value.
699 */
700 public static String setToString(int set) {
701 switch (set) {
702 case SET_ALL:
703 return "ALL";
704 case SET_DEFAULT:
705 return "DEFAULT";
706 case SET_FOREGROUND:
707 return "FOREGROUND";
708 default:
709 return "UNKNOWN";
710 }
711 }
712
713 /**
714 * Return text description of {@link #tag} value.
715 */
716 public static String tagToString(int tag) {
717 return "0x" + Integer.toHexString(tag);
718 }
719
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700720 @Override
721 public String toString() {
722 final CharArrayWriter writer = new CharArrayWriter();
723 dump("", new PrintWriter(writer));
724 return writer.toString();
725 }
726
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700727 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700728 public int describeContents() {
729 return 0;
730 }
731
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700732 public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700733 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700734 public NetworkStats createFromParcel(Parcel in) {
735 return new NetworkStats(in);
736 }
737
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700738 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700739 public NetworkStats[] newArray(int size) {
740 return new NetworkStats[size];
741 }
742 };
Jeff Sharkey163e6442011-10-31 16:37:52 -0700743
Jeff Sharkey63abc372012-01-11 18:38:16 -0800744 public interface NonMonotonicObserver<C> {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800745 public void foundNonMonotonic(
Jeff Sharkey63abc372012-01-11 18:38:16 -0800746 NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
Jeff Sharkey163e6442011-10-31 16:37:52 -0700747 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700748}