blob: 60f740e80f53653374bd0f072f6bf4f166e279b6 [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
24import java.io.CharArrayWriter;
25import java.io.PrintWriter;
Jeff Sharkey4a971222011-06-11 22:16:55 -070026import java.util.Arrays;
Jeff Sharkey75279902011-05-24 18:39:45 -070027import java.util.HashSet;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070028
29/**
Jeff Sharkey75279902011-05-24 18:39:45 -070030 * Collection of active network statistics. Can contain summary details across
31 * all interfaces, or details with per-UID granularity. Internally stores data
32 * as a large table, closely matching {@code /proc/} data format. This structure
33 * optimizes for rapid in-memory comparison, but consider using
34 * {@link NetworkStatsHistory} when persisting.
Jeff Sharkey9a13f362011-04-26 16:25:36 -070035 *
36 * @hide
37 */
38public class NetworkStats implements Parcelable {
Jeff Sharkey75279902011-05-24 18:39:45 -070039 /** {@link #iface} value when interface details unavailable. */
Jeff Sharkey9a13f362011-04-26 16:25:36 -070040 public static final String IFACE_ALL = null;
Jeff Sharkey75279902011-05-24 18:39:45 -070041 /** {@link #uid} value when UID details unavailable. */
42 public static final int UID_ALL = -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070043
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070044 // NOTE: data should only be accounted for once in this structure; if data
45 // is broken out, the summarized version should not be included.
46
Jeff Sharkey9a13f362011-04-26 16:25:36 -070047 /**
48 * {@link SystemClock#elapsedRealtime()} timestamp when this data was
49 * generated.
50 */
51 public final long elapsedRealtime;
Jeff Sharkey4a971222011-06-11 22:16:55 -070052 public int size;
53 public String[] iface;
54 public int[] uid;
55 public long[] rx;
56 public long[] tx;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070057
Jeff Sharkey75279902011-05-24 18:39:45 -070058 // TODO: add fg/bg stats once reported by kernel
Jeff Sharkey9a13f362011-04-26 16:25:36 -070059
Jeff Sharkey4a971222011-06-11 22:16:55 -070060 public NetworkStats(long elapsedRealtime, int initialSize) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -070061 this.elapsedRealtime = elapsedRealtime;
Jeff Sharkey4a971222011-06-11 22:16:55 -070062 this.size = 0;
63 this.iface = new String[initialSize];
64 this.uid = new int[initialSize];
65 this.rx = new long[initialSize];
66 this.tx = new long[initialSize];
Jeff Sharkey9a13f362011-04-26 16:25:36 -070067 }
68
69 public NetworkStats(Parcel parcel) {
70 elapsedRealtime = parcel.readLong();
Jeff Sharkey4a971222011-06-11 22:16:55 -070071 size = parcel.readInt();
Jeff Sharkey9a13f362011-04-26 16:25:36 -070072 iface = parcel.createStringArray();
73 uid = parcel.createIntArray();
74 rx = parcel.createLongArray();
75 tx = parcel.createLongArray();
76 }
77
Jeff Sharkey4a971222011-06-11 22:16:55 -070078 public NetworkStats addEntry(String iface, int uid, long rx, long tx) {
79 if (size >= this.iface.length) {
80 final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
81 this.iface = Arrays.copyOf(this.iface, newLength);
82 this.uid = Arrays.copyOf(this.uid, newLength);
83 this.rx = Arrays.copyOf(this.rx, newLength);
84 this.tx = Arrays.copyOf(this.tx, newLength);
Jeff Sharkey9a13f362011-04-26 16:25:36 -070085 }
86
Jeff Sharkey4a971222011-06-11 22:16:55 -070087 this.iface[size] = iface;
88 this.uid[size] = uid;
89 this.rx[size] = rx;
90 this.tx[size] = tx;
91 size++;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070092
Jeff Sharkey4a971222011-06-11 22:16:55 -070093 return this;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070094 }
95
Jeff Sharkey4a971222011-06-11 22:16:55 -070096 @Deprecated
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070097 public int length() {
Jeff Sharkey4a971222011-06-11 22:16:55 -070098 return size;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070099 }
100
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700101 /**
102 * Find first stats index that matches the requested parameters.
103 */
104 public int findIndex(String iface, int uid) {
Jeff Sharkey4a971222011-06-11 22:16:55 -0700105 for (int i = 0; i < size; i++) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700106 if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
107 return i;
108 }
109 }
110 return -1;
111 }
112
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700113 /**
Jeff Sharkey75279902011-05-24 18:39:45 -0700114 * Return list of unique interfaces known by this data structure.
115 */
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700116 public String[] getUniqueIfaces() {
Jeff Sharkey75279902011-05-24 18:39:45 -0700117 final HashSet<String> ifaces = new HashSet<String>();
118 for (String iface : this.iface) {
119 if (iface != IFACE_ALL) {
120 ifaces.add(iface);
121 }
122 }
123 return ifaces.toArray(new String[ifaces.size()]);
124 }
125
126 /**
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700127 * Return list of unique UIDs known by this data structure.
128 */
129 public int[] getUniqueUids() {
130 final SparseBooleanArray uids = new SparseBooleanArray();
131 for (int uid : this.uid) {
132 uids.put(uid, true);
133 }
134
135 final int size = uids.size();
136 final int[] result = new int[size];
137 for (int i = 0; i < size; i++) {
138 result[i] = uids.keyAt(i);
139 }
140 return result;
141 }
142
143 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700144 * Subtract the given {@link NetworkStats}, effectively leaving the delta
145 * between two snapshots in time. Assumes that statistics rows collect over
146 * time, and that none of them have disappeared.
Jeff Sharkey75279902011-05-24 18:39:45 -0700147 *
Jeff Sharkey3f391352011-06-05 17:42:53 -0700148 * @throws IllegalArgumentException when given {@link NetworkStats} is
149 * non-monotonic.
150 */
151 public NetworkStats subtract(NetworkStats value) {
152 return subtract(value, true, false);
153 }
154
155 /**
156 * Subtract the given {@link NetworkStats}, effectively leaving the delta
157 * between two snapshots in time. Assumes that statistics rows collect over
158 * time, and that none of them have disappeared.
159 * <p>
160 * Instead of throwing when counters are non-monotonic, this variant clamps
161 * results to never be negative.
162 */
163 public NetworkStats subtractClamped(NetworkStats value) {
164 return subtract(value, false, true);
165 }
166
167 /**
168 * Subtract the given {@link NetworkStats}, effectively leaving the delta
169 * between two snapshots in time. Assumes that statistics rows collect over
170 * time, and that none of them have disappeared.
171 *
Jeff Sharkey75279902011-05-24 18:39:45 -0700172 * @param enforceMonotonic Validate that incoming value is strictly
173 * monotonic compared to this object.
Jeff Sharkey3f391352011-06-05 17:42:53 -0700174 * @param clampNegative Instead of throwing like {@code enforceMonotonic},
175 * clamp resulting counters at 0 to prevent negative values.
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700176 */
Jeff Sharkey3f391352011-06-05 17:42:53 -0700177 private NetworkStats subtract(
178 NetworkStats value, boolean enforceMonotonic, boolean clampNegative) {
Jeff Sharkey75279902011-05-24 18:39:45 -0700179 final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
180 if (enforceMonotonic && deltaRealtime < 0) {
181 throw new IllegalArgumentException("found non-monotonic realtime");
182 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700183
Jeff Sharkey75279902011-05-24 18:39:45 -0700184 // result will have our rows, and elapsed time between snapshots
Jeff Sharkey4a971222011-06-11 22:16:55 -0700185 final NetworkStats result = new NetworkStats(deltaRealtime, size);
186 for (int i = 0; i < size; i++) {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700187 final String iface = this.iface[i];
188 final int uid = this.uid[i];
189
190 // find remote row that matches, and subtract
191 final int j = value.findIndex(iface, uid);
192 if (j == -1) {
193 // newly appearing row, return entire value
194 result.addEntry(iface, uid, this.rx[i], this.tx[i]);
195 } else {
196 // existing row, subtract remote value
Jeff Sharkey3f391352011-06-05 17:42:53 -0700197 long rx = this.rx[i] - value.rx[j];
198 long tx = this.tx[i] - value.tx[j];
Jeff Sharkey75279902011-05-24 18:39:45 -0700199 if (enforceMonotonic && (rx < 0 || tx < 0)) {
200 throw new IllegalArgumentException("found non-monotonic values");
201 }
Jeff Sharkey3f391352011-06-05 17:42:53 -0700202 if (clampNegative) {
203 rx = Math.max(0, rx);
204 tx = Math.max(0, tx);
205 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700206 result.addEntry(iface, uid, rx, tx);
207 }
208 }
209
Jeff Sharkey4a971222011-06-11 22:16:55 -0700210 return result;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700211 }
212
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700213 private static boolean equal(Object a, Object b) {
214 return a == b || (a != null && a.equals(b));
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700215 }
216
217 public void dump(String prefix, PrintWriter pw) {
218 pw.print(prefix);
219 pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
220 for (int i = 0; i < iface.length; i++) {
221 pw.print(prefix);
222 pw.print(" iface="); pw.print(iface[i]);
223 pw.print(" uid="); pw.print(uid[i]);
224 pw.print(" rx="); pw.print(rx[i]);
225 pw.print(" tx="); pw.println(tx[i]);
226 }
227 }
228
229 @Override
230 public String toString() {
231 final CharArrayWriter writer = new CharArrayWriter();
232 dump("", new PrintWriter(writer));
233 return writer.toString();
234 }
235
236 /** {@inheritDoc} */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700237 public int describeContents() {
238 return 0;
239 }
240
241 /** {@inheritDoc} */
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700242 public void writeToParcel(Parcel dest, int flags) {
243 dest.writeLong(elapsedRealtime);
Jeff Sharkey4a971222011-06-11 22:16:55 -0700244 dest.writeInt(size);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700245 dest.writeStringArray(iface);
246 dest.writeIntArray(uid);
247 dest.writeLongArray(rx);
248 dest.writeLongArray(tx);
249 }
250
251 public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
252 public NetworkStats createFromParcel(Parcel in) {
253 return new NetworkStats(in);
254 }
255
256 public NetworkStats[] newArray(int size) {
257 return new NetworkStats[size];
258 }
259 };
260}