blob: 3924f136edd8d11e0749c86cedb96d2ce354ba9a [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
Jeff Sharkey163e6442011-10-31 16:37:52 -070019import static com.android.internal.util.Preconditions.checkNotNull;
20
Jeff Sharkey9a13f362011-04-26 16:25:36 -070021import android.os.Parcel;
22import android.os.Parcelable;
23import android.os.SystemClock;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070024import android.util.SparseBooleanArray;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070025
Jeff Sharkeya63ba592011-07-19 23:47:12 -070026import com.android.internal.util.Objects;
27
Jeff Sharkey9a13f362011-04-26 16:25:36 -070028import java.io.CharArrayWriter;
29import java.io.PrintWriter;
Jeff Sharkey4a971222011-06-11 22:16:55 -070030import java.util.Arrays;
Jeff Sharkey75279902011-05-24 18:39:45 -070031import java.util.HashSet;
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 Sharkey47eb1022011-08-25 17:48:52 -070043 private static final String TAG = "NetworkStats";
44
Jeff Sharkey75279902011-05-24 18:39:45 -070045 /** {@link #iface} value when interface details unavailable. */
Jeff Sharkey9a13f362011-04-26 16:25:36 -070046 public static final String IFACE_ALL = null;
Jeff Sharkey75279902011-05-24 18:39:45 -070047 /** {@link #uid} value when UID details unavailable. */
48 public static final int UID_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 */
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070064 private final long elapsedRealtime;
65 private int size;
66 private String[] iface;
67 private int[] uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070068 private int[] set;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070069 private int[] tag;
70 private long[] rxBytes;
71 private long[] rxPackets;
72 private long[] txBytes;
73 private long[] txPackets;
Jeff Sharkey63d27a92011-08-03 17:04:22 -070074 private long[] operations;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070075
76 public static class Entry {
77 public String iface;
78 public int uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070079 public int set;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070080 public int tag;
81 public long rxBytes;
82 public long rxPackets;
83 public long txBytes;
84 public long txPackets;
Jeff Sharkey63d27a92011-08-03 17:04:22 -070085 public long operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070086
87 public Entry() {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070088 this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
Jeff Sharkey63d27a92011-08-03 17:04:22 -070089 }
90
91 public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070092 this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
93 operations);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070094 }
95
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070096 public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
97 long txBytes, long txPackets, long operations) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -070098 this.iface = iface;
99 this.uid = uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700100 this.set = set;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700101 this.tag = tag;
102 this.rxBytes = rxBytes;
103 this.rxPackets = rxPackets;
104 this.txBytes = txBytes;
105 this.txPackets = txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700106 this.operations = operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700107 }
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700108
109 @Override
110 public String toString() {
111 final StringBuilder builder = new StringBuilder();
112 builder.append("iface=").append(iface);
113 builder.append(" uid=").append(uid);
114 builder.append(" set=").append(setToString(set));
115 builder.append(" tag=").append(tagToString(tag));
116 builder.append(" rxBytes=").append(rxBytes);
117 builder.append(" rxPackets=").append(rxPackets);
118 builder.append(" txBytes=").append(txBytes);
119 builder.append(" txPackets=").append(txPackets);
120 builder.append(" operations=").append(operations);
121 return builder.toString();
122 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700123 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700124
Jeff Sharkey4a971222011-06-11 22:16:55 -0700125 public NetworkStats(long elapsedRealtime, int initialSize) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700126 this.elapsedRealtime = elapsedRealtime;
Jeff Sharkey4a971222011-06-11 22:16:55 -0700127 this.size = 0;
128 this.iface = new String[initialSize];
129 this.uid = new int[initialSize];
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700130 this.set = new int[initialSize];
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700131 this.tag = new int[initialSize];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700132 this.rxBytes = new long[initialSize];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700133 this.rxPackets = new long[initialSize];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700134 this.txBytes = new long[initialSize];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700135 this.txPackets = new long[initialSize];
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700136 this.operations = new long[initialSize];
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700137 }
138
139 public NetworkStats(Parcel parcel) {
140 elapsedRealtime = parcel.readLong();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700141 size = parcel.readInt();
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700142 iface = parcel.createStringArray();
143 uid = parcel.createIntArray();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700144 set = parcel.createIntArray();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700145 tag = parcel.createIntArray();
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700146 rxBytes = parcel.createLongArray();
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700147 rxPackets = parcel.createLongArray();
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700148 txBytes = parcel.createLongArray();
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700149 txPackets = parcel.createLongArray();
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700150 operations = parcel.createLongArray();
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700151 }
152
153 /** {@inheritDoc} */
154 public void writeToParcel(Parcel dest, int flags) {
155 dest.writeLong(elapsedRealtime);
156 dest.writeInt(size);
157 dest.writeStringArray(iface);
158 dest.writeIntArray(uid);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700159 dest.writeIntArray(set);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700160 dest.writeIntArray(tag);
161 dest.writeLongArray(rxBytes);
162 dest.writeLongArray(rxPackets);
163 dest.writeLongArray(txBytes);
164 dest.writeLongArray(txPackets);
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700165 dest.writeLongArray(operations);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700166 }
167
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700168 // @VisibleForTesting
169 public NetworkStats addIfaceValues(
170 String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
171 return addValues(
172 iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700173 }
174
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700175 // @VisibleForTesting
176 public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
177 long rxPackets, long txBytes, long txPackets, long operations) {
178 return addValues(new Entry(
179 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700180 }
181
182 /**
183 * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
184 * object can be recycled across multiple calls.
185 */
186 public NetworkStats addValues(Entry entry) {
Jeff Sharkey4a971222011-06-11 22:16:55 -0700187 if (size >= this.iface.length) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700188 final int newLength = Math.max(iface.length, 10) * 3 / 2;
189 iface = Arrays.copyOf(iface, newLength);
190 uid = Arrays.copyOf(uid, newLength);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700191 set = Arrays.copyOf(set, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700192 tag = Arrays.copyOf(tag, newLength);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700193 rxBytes = Arrays.copyOf(rxBytes, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700194 rxPackets = Arrays.copyOf(rxPackets, newLength);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700195 txBytes = Arrays.copyOf(txBytes, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700196 txPackets = Arrays.copyOf(txPackets, newLength);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700197 operations = Arrays.copyOf(operations, newLength);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700198 }
199
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700200 iface[size] = entry.iface;
201 uid[size] = entry.uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700202 set[size] = entry.set;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700203 tag[size] = entry.tag;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700204 rxBytes[size] = entry.rxBytes;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700205 rxPackets[size] = entry.rxPackets;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700206 txBytes[size] = entry.txBytes;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700207 txPackets[size] = entry.txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700208 operations[size] = entry.operations;
Jeff Sharkey4a971222011-06-11 22:16:55 -0700209 size++;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700210
Jeff Sharkey4a971222011-06-11 22:16:55 -0700211 return this;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700212 }
213
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700214 /**
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700215 * Return specific stats entry.
216 */
217 public Entry getValues(int i, Entry recycle) {
218 final Entry entry = recycle != null ? recycle : new Entry();
219 entry.iface = iface[i];
220 entry.uid = uid[i];
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700221 entry.set = set[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700222 entry.tag = tag[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700223 entry.rxBytes = rxBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700224 entry.rxPackets = rxPackets[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700225 entry.txBytes = txBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700226 entry.txPackets = txPackets[i];
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700227 entry.operations = operations[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700228 return entry;
229 }
230
231 public long getElapsedRealtime() {
232 return elapsedRealtime;
233 }
234
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700235 /**
236 * Return age of this {@link NetworkStats} object with respect to
237 * {@link SystemClock#elapsedRealtime()}.
238 */
239 public long getElapsedRealtimeAge() {
240 return SystemClock.elapsedRealtime() - elapsedRealtime;
241 }
242
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700243 public int size() {
244 return size;
245 }
246
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700247 // @VisibleForTesting
248 public int internalSize() {
249 return iface.length;
250 }
251
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700252 @Deprecated
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700253 public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700254 long txBytes, long txPackets, long operations) {
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700255 return combineValues(
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700256 iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations);
257 }
258
259 public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes,
260 long rxPackets, long txBytes, long txPackets, long operations) {
261 return combineValues(new Entry(
262 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700263 }
264
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700265 /**
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700266 * Combine given values with an existing row, or create a new row if
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700267 * {@link #findIndex(String, int, int, int)} is unable to find match. Can
268 * also be used to subtract values from existing rows.
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700269 */
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700270 public NetworkStats combineValues(Entry entry) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700271 final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700272 if (i == -1) {
273 // only create new entry when positive contribution
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700274 addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700275 } else {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700276 rxBytes[i] += entry.rxBytes;
277 rxPackets[i] += entry.rxPackets;
278 txBytes[i] += entry.txBytes;
279 txPackets[i] += entry.txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700280 operations[i] += entry.operations;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700281 }
282 return this;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700283 }
284
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700285 /**
Jeff Sharkey905b5892011-09-30 15:19:49 -0700286 * Combine all values from another {@link NetworkStats} into this object.
287 */
288 public void combineAllValues(NetworkStats another) {
289 NetworkStats.Entry entry = null;
290 for (int i = 0; i < another.size; i++) {
291 entry = another.getValues(i, entry);
292 combineValues(entry);
293 }
294 }
295
296 /**
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700297 * Find first stats index that matches the requested parameters.
298 */
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700299 public int findIndex(String iface, int uid, int set, int tag) {
Jeff Sharkey4a971222011-06-11 22:16:55 -0700300 for (int i = 0; i < size; i++) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700301 if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
302 && Objects.equal(iface, this.iface[i])) {
303 return i;
304 }
305 }
306 return -1;
307 }
308
309 /**
310 * Find first stats index that matches the requested parameters, starting
311 * search around the hinted index as an optimization.
312 */
313 // @VisibleForTesting
314 public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) {
315 for (int offset = 0; offset < size; offset++) {
316 final int halfOffset = offset / 2;
317
318 // search outwards from hint index, alternating forward and backward
319 final int i;
320 if (offset % 2 == 0) {
321 i = (hintIndex + halfOffset) % size;
322 } else {
323 i = (size + hintIndex - halfOffset - 1) % size;
324 }
325
326 if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
327 && Objects.equal(iface, this.iface[i])) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700328 return i;
329 }
330 }
331 return -1;
332 }
333
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700334 /**
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700335 * Splice in {@link #operations} from the given {@link NetworkStats} based
336 * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
337 * since operation counts are at data layer.
338 */
339 public void spliceOperationsFrom(NetworkStats stats) {
340 for (int i = 0; i < size; i++) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700341 final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700342 if (j == -1) {
343 operations[i] = 0;
344 } else {
345 operations[i] = stats.operations[j];
346 }
347 }
348 }
349
350 /**
Jeff Sharkey75279902011-05-24 18:39:45 -0700351 * Return list of unique interfaces known by this data structure.
352 */
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700353 public String[] getUniqueIfaces() {
Jeff Sharkey75279902011-05-24 18:39:45 -0700354 final HashSet<String> ifaces = new HashSet<String>();
355 for (String iface : this.iface) {
356 if (iface != IFACE_ALL) {
357 ifaces.add(iface);
358 }
359 }
360 return ifaces.toArray(new String[ifaces.size()]);
361 }
362
363 /**
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700364 * Return list of unique UIDs known by this data structure.
365 */
366 public int[] getUniqueUids() {
367 final SparseBooleanArray uids = new SparseBooleanArray();
368 for (int uid : this.uid) {
369 uids.put(uid, true);
370 }
371
372 final int size = uids.size();
373 final int[] result = new int[size];
374 for (int i = 0; i < size; i++) {
375 result[i] = uids.keyAt(i);
376 }
377 return result;
378 }
379
380 /**
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700381 * Return total bytes represented by this snapshot object, usually used when
382 * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
383 */
384 public long getTotalBytes() {
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700385 final Entry entry = getTotal(null);
386 return entry.rxBytes + entry.txBytes;
387 }
388
389 /**
390 * Return total of all fields represented by this snapshot object.
391 */
392 public Entry getTotal(Entry recycle) {
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700393 return getTotal(recycle, null, UID_ALL);
394 }
395
396 /**
397 * Return total of all fields represented by this snapshot object matching
398 * the requested {@link #uid}.
399 */
400 public Entry getTotal(Entry recycle, int limitUid) {
401 return getTotal(recycle, null, limitUid);
402 }
403
404 /**
405 * Return total of all fields represented by this snapshot object matching
406 * the requested {@link #iface}.
407 */
408 public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
409 return getTotal(recycle, limitIface, UID_ALL);
410 }
411
412 /**
413 * Return total of all fields represented by this snapshot object matching
414 * the requested {@link #iface} and {@link #uid}.
415 *
416 * @param limitIface Set of {@link #iface} to include in total; or {@code
417 * null} to include all ifaces.
418 */
419 private Entry getTotal(Entry recycle, HashSet<String> limitIface, int limitUid) {
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700420 final Entry entry = recycle != null ? recycle : new Entry();
421
422 entry.iface = IFACE_ALL;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700423 entry.uid = limitUid;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700424 entry.set = SET_ALL;
425 entry.tag = TAG_NONE;
426 entry.rxBytes = 0;
427 entry.rxPackets = 0;
428 entry.txBytes = 0;
429 entry.txPackets = 0;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700430 entry.operations = 0;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700431
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700432 for (int i = 0; i < size; i++) {
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700433 final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
434 final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700435
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700436 if (matchesUid && matchesIface) {
437 // skip specific tags, since already counted in TAG_NONE
438 if (tag[i] != TAG_NONE) continue;
439
440 entry.rxBytes += rxBytes[i];
441 entry.rxPackets += rxPackets[i];
442 entry.txBytes += txBytes[i];
443 entry.txPackets += txPackets[i];
444 entry.operations += operations[i];
445 }
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700446 }
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700447 return entry;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700448 }
449
450 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700451 * Subtract the given {@link NetworkStats}, effectively leaving the delta
452 * between two snapshots in time. Assumes that statistics rows collect over
453 * time, and that none of them have disappeared.
Jeff Sharkey3f391352011-06-05 17:42:53 -0700454 */
Jeff Sharkey163e6442011-10-31 16:37:52 -0700455 public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
Jeff Sharkey75279902011-05-24 18:39:45 -0700456 final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700457 if (deltaRealtime < 0) {
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800458 throw new NonMonotonicException(this, value);
Jeff Sharkey75279902011-05-24 18:39:45 -0700459 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700460
Jeff Sharkey75279902011-05-24 18:39:45 -0700461 // result will have our rows, and elapsed time between snapshots
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700462 final Entry entry = new Entry();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700463 final NetworkStats result = new NetworkStats(deltaRealtime, size);
464 for (int i = 0; i < size; i++) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700465 entry.iface = iface[i];
466 entry.uid = uid[i];
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700467 entry.set = set[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700468 entry.tag = tag[i];
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700469
470 // find remote row that matches, and subtract
Jeff Sharkey163e6442011-10-31 16:37:52 -0700471 final int j = value.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700472 if (j == -1) {
473 // newly appearing row, return entire value
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700474 entry.rxBytes = rxBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700475 entry.rxPackets = rxPackets[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700476 entry.txBytes = txBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700477 entry.txPackets = txPackets[i];
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700478 entry.operations = operations[i];
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700479 } else {
480 // existing row, subtract remote value
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700481 entry.rxBytes = rxBytes[i] - value.rxBytes[j];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700482 entry.rxPackets = rxPackets[i] - value.rxPackets[j];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700483 entry.txBytes = txBytes[i] - value.txBytes[j];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700484 entry.txPackets = txPackets[i] - value.txPackets[j];
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700485 entry.operations = operations[i] - value.operations[j];
Jeff Sharkey163e6442011-10-31 16:37:52 -0700486
487 if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
488 || entry.txPackets < 0 || entry.operations < 0) {
489 throw new NonMonotonicException(this, i, value, j);
Jeff Sharkey3f391352011-06-05 17:42:53 -0700490 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700491 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700492
493 result.addValues(entry);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700494 }
495
Jeff Sharkey4a971222011-06-11 22:16:55 -0700496 return result;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700497 }
498
Jeff Sharkey905b5892011-09-30 15:19:49 -0700499 /**
500 * Return total statistics grouped by {@link #iface}; doesn't mutate the
501 * original structure.
502 */
503 public NetworkStats groupedByIface() {
504 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
505
506 final Entry entry = new Entry();
507 entry.uid = UID_ALL;
508 entry.set = SET_ALL;
509 entry.tag = TAG_NONE;
510 entry.operations = 0L;
511
512 for (int i = 0; i < size; i++) {
513 // skip specific tags, since already counted in TAG_NONE
514 if (tag[i] != TAG_NONE) continue;
515
516 entry.iface = iface[i];
517 entry.rxBytes = rxBytes[i];
518 entry.rxPackets = rxPackets[i];
519 entry.txBytes = txBytes[i];
520 entry.txPackets = txPackets[i];
521 stats.combineValues(entry);
522 }
523
524 return stats;
525 }
526
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700527 /**
528 * Return total statistics grouped by {@link #uid}; doesn't mutate the
529 * original structure.
530 */
531 public NetworkStats groupedByUid() {
532 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
533
534 final Entry entry = new Entry();
535 entry.iface = IFACE_ALL;
536 entry.set = SET_ALL;
537 entry.tag = TAG_NONE;
538
539 for (int i = 0; i < size; i++) {
540 // skip specific tags, since already counted in TAG_NONE
541 if (tag[i] != TAG_NONE) continue;
542
543 entry.uid = uid[i];
544 entry.rxBytes = rxBytes[i];
545 entry.rxPackets = rxPackets[i];
546 entry.txBytes = txBytes[i];
547 entry.txPackets = txPackets[i];
548 entry.operations = operations[i];
549 stats.combineValues(entry);
550 }
551
552 return stats;
553 }
554
Jeff Sharkey163e6442011-10-31 16:37:52 -0700555 /**
556 * Return all rows except those attributed to the requested UID; doesn't
557 * mutate the original structure.
558 */
559 public NetworkStats withoutUid(int uid) {
560 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
561
562 Entry entry = new Entry();
563 for (int i = 0; i < size; i++) {
564 entry = getValues(i, entry);
565 if (entry.uid != uid) {
566 stats.addValues(entry);
567 }
568 }
569
570 return stats;
571 }
572
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700573 public void dump(String prefix, PrintWriter pw) {
574 pw.print(prefix);
575 pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700576 for (int i = 0; i < size; i++) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700577 pw.print(prefix);
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800578 pw.print(" ["); pw.print(i); pw.print("]");
579 pw.print(" iface="); pw.print(iface[i]);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700580 pw.print(" uid="); pw.print(uid[i]);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700581 pw.print(" set="); pw.print(setToString(set[i]));
582 pw.print(" tag="); pw.print(tagToString(tag[i]));
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700583 pw.print(" rxBytes="); pw.print(rxBytes[i]);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700584 pw.print(" rxPackets="); pw.print(rxPackets[i]);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700585 pw.print(" txBytes="); pw.print(txBytes[i]);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700586 pw.print(" txPackets="); pw.print(txPackets[i]);
587 pw.print(" operations="); pw.println(operations[i]);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700588 }
589 }
590
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700591 /**
592 * Return text description of {@link #set} value.
593 */
594 public static String setToString(int set) {
595 switch (set) {
596 case SET_ALL:
597 return "ALL";
598 case SET_DEFAULT:
599 return "DEFAULT";
600 case SET_FOREGROUND:
601 return "FOREGROUND";
602 default:
603 return "UNKNOWN";
604 }
605 }
606
607 /**
608 * Return text description of {@link #tag} value.
609 */
610 public static String tagToString(int tag) {
611 return "0x" + Integer.toHexString(tag);
612 }
613
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700614 @Override
615 public String toString() {
616 final CharArrayWriter writer = new CharArrayWriter();
617 dump("", new PrintWriter(writer));
618 return writer.toString();
619 }
620
621 /** {@inheritDoc} */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700622 public int describeContents() {
623 return 0;
624 }
625
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700626 public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
627 public NetworkStats createFromParcel(Parcel in) {
628 return new NetworkStats(in);
629 }
630
631 public NetworkStats[] newArray(int size) {
632 return new NetworkStats[size];
633 }
634 };
Jeff Sharkey163e6442011-10-31 16:37:52 -0700635
636 public static class NonMonotonicException extends Exception {
637 public final NetworkStats left;
638 public final NetworkStats right;
639 public final int leftIndex;
640 public final int rightIndex;
641
Jeff Sharkey3359aca2011-11-08 18:08:48 -0800642 public NonMonotonicException(NetworkStats left, NetworkStats right) {
643 this(left, -1, right, -1);
644 }
645
Jeff Sharkey163e6442011-10-31 16:37:52 -0700646 public NonMonotonicException(
647 NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
648 this.left = checkNotNull(left, "missing left");
649 this.right = checkNotNull(right, "missing right");
650 this.leftIndex = leftIndex;
651 this.rightIndex = rightIndex;
652 }
653 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700654}