blob: 9cf582bef1d43b15bc6403d8d1a184053446c76f [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
junyulaif6ebf4a2018-10-30 21:49:38 +080019import static android.os.Process.CLAT_UID;
20
Mathew Inwoodfa3a7462018-08-08 14:52:47 +010021import android.annotation.UnsupportedAppUsage;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070022import android.os.Parcel;
23import android.os.Parcelable;
24import android.os.SystemClock;
Wenchao Tong21377c32015-02-26 18:13:07 -080025import android.util.Slog;
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -070026import android.util.SparseBooleanArray;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070027
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080028import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkeydaa57e82012-09-19 14:10:39 -070029import com.android.internal.util.ArrayUtils;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070030
Jeff Sharkey7a8f1a32014-09-17 09:26:28 -070031import libcore.util.EmptyArray;
32
Jeff Sharkey9a13f362011-04-26 16:25:36 -070033import java.io.CharArrayWriter;
34import java.io.PrintWriter;
Jeff Sharkey4a971222011-06-11 22:16:55 -070035import java.util.Arrays;
Jeff Sharkey75279902011-05-24 18:39:45 -070036import java.util.HashSet;
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +090037import java.util.Map;
Kenny Roote6585b32013-12-13 12:00:26 -080038import java.util.Objects;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070039
40/**
Jeff Sharkey75279902011-05-24 18:39:45 -070041 * Collection of active network statistics. Can contain summary details across
42 * all interfaces, or details with per-UID granularity. Internally stores data
43 * as a large table, closely matching {@code /proc/} data format. This structure
44 * optimizes for rapid in-memory comparison, but consider using
45 * {@link NetworkStatsHistory} when persisting.
Jeff Sharkey9a13f362011-04-26 16:25:36 -070046 *
47 * @hide
48 */
junyulai8b8684a2018-10-29 22:26:22 +080049// @NotThreadSafe
Jeff Sharkey9a13f362011-04-26 16:25:36 -070050public class NetworkStats implements Parcelable {
Wenchao Tong21377c32015-02-26 18:13:07 -080051 private static final String TAG = "NetworkStats";
Jeff Sharkey75279902011-05-24 18:39:45 -070052 /** {@link #iface} value when interface details unavailable. */
Jeff Sharkey9a13f362011-04-26 16:25:36 -070053 public static final String IFACE_ALL = null;
Jeff Sharkey75279902011-05-24 18:39:45 -070054 /** {@link #uid} value when UID details unavailable. */
55 public static final int UID_ALL = -1;
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -080056 /** {@link #tag} value matching any tag. */
Antonio Cansado46c753672015-12-10 15:57:56 -080057 // TODO: Rename TAG_ALL to TAG_ANY.
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -080058 public static final int TAG_ALL = -1;
Jeff Davidsona6a78072016-01-11 16:02:17 -080059 /** {@link #set} value for all sets combined, not including debug sets. */
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070060 public static final int SET_ALL = -1;
61 /** {@link #set} value where background data is accounted. */
62 public static final int SET_DEFAULT = 0;
63 /** {@link #set} value where foreground data is accounted. */
64 public static final int SET_FOREGROUND = 1;
Wenchao Tong98170b02015-03-17 16:14:23 -070065 /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */
66 public static final int SET_DEBUG_START = 1000;
67 /** Debug {@link #set} value when the VPN stats are moved in. */
68 public static final int SET_DBG_VPN_IN = 1001;
69 /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
70 public static final int SET_DBG_VPN_OUT = 1002;
71
Remi NGUYEN VANb6a92012018-03-06 12:36:54 +090072 /** Include all interfaces when filtering */
73 public static final String[] INTERFACES_ALL = null;
74
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070075 /** {@link #tag} value for total data across all tags. */
Antonio Cansado46c753672015-12-10 15:57:56 -080076 // TODO: Rename TAG_NONE to TAG_ALL.
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070077 public static final int TAG_NONE = 0;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070078
Stephen Chen25147872016-10-21 12:44:26 -070079 /** {@link #metered} value to account for all metered states. */
80 public static final int METERED_ALL = -1;
81 /** {@link #metered} value where native, unmetered data is accounted. */
82 public static final int METERED_NO = 0;
83 /** {@link #metered} value where metered data is accounted. */
84 public static final int METERED_YES = 1;
85
86 /** {@link #roaming} value to account for all roaming states. */
Jeff Davidsona6a78072016-01-11 16:02:17 -080087 public static final int ROAMING_ALL = -1;
Stephen Chen25147872016-10-21 12:44:26 -070088 /** {@link #roaming} value where native, non-roaming data is accounted. */
Jeff Davidson1f7e05e2016-03-10 13:21:38 -080089 public static final int ROAMING_NO = 0;
Stephen Chen25147872016-10-21 12:44:26 -070090 /** {@link #roaming} value where roaming data is accounted. */
Jeff Davidson1f7e05e2016-03-10 13:21:38 -080091 public static final int ROAMING_YES = 1;
Jeff Davidsona6a78072016-01-11 16:02:17 -080092
Lorenzo Colittiada23ed2018-01-19 01:05:20 +090093 /** {@link #onDefaultNetwork} value to account for all default network states. */
94 public static final int DEFAULT_NETWORK_ALL = -1;
95 /** {@link #onDefaultNetwork} value to account for usage while not the default network. */
96 public static final int DEFAULT_NETWORK_NO = 0;
97 /** {@link #onDefaultNetwork} value to account for usage while the default network. */
98 public static final int DEFAULT_NETWORK_YES = 1;
99
Lorenzo Colittif1912ca2017-08-17 19:23:08 +0900100 /** Denotes a request for stats at the interface level. */
101 public static final int STATS_PER_IFACE = 0;
102 /** Denotes a request for stats at the interface and UID level. */
103 public static final int STATS_PER_UID = 1;
104
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900105 private static final String CLATD_INTERFACE_PREFIX = "v4-";
106 // Delta between IPv4 header (20b) and IPv6 header (40b).
107 // Used for correct stats accounting on clatd interfaces.
108 private static final int IPV4V6_HEADER_DELTA = 20;
109
Jeff Sharkey163e6442011-10-31 16:37:52 -0700110 // TODO: move fields to "mVariable" notation
111
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700112 /**
113 * {@link SystemClock#elapsedRealtime()} timestamp when this data was
114 * generated.
115 */
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800116 private long elapsedRealtime;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100117 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700118 private int size;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100119 @UnsupportedAppUsage
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800120 private int capacity;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100121 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700122 private String[] iface;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100123 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700124 private int[] uid;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100125 @UnsupportedAppUsage
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700126 private int[] set;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100127 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700128 private int[] tag;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100129 @UnsupportedAppUsage
Stephen Chen25147872016-10-21 12:44:26 -0700130 private int[] metered;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100131 @UnsupportedAppUsage
Jeff Davidsona6a78072016-01-11 16:02:17 -0800132 private int[] roaming;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100133 @UnsupportedAppUsage
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900134 private int[] defaultNetwork;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100135 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700136 private long[] rxBytes;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100137 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700138 private long[] rxPackets;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100139 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700140 private long[] txBytes;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100141 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700142 private long[] txPackets;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100143 @UnsupportedAppUsage
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700144 private long[] operations;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700145
146 public static class Entry {
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100147 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700148 public String iface;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100149 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700150 public int uid;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100151 @UnsupportedAppUsage
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700152 public int set;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100153 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700154 public int tag;
Jeff Davidsona6a78072016-01-11 16:02:17 -0800155 /**
156 * Note that this is only populated w/ the default value when read from /proc or written
157 * to disk. We merge in the correct value when reporting this value to clients of
158 * getSummary().
159 */
Stephen Chen25147872016-10-21 12:44:26 -0700160 public int metered;
161 /**
162 * Note that this is only populated w/ the default value when read from /proc or written
163 * to disk. We merge in the correct value when reporting this value to clients of
164 * getSummary().
165 */
Jeff Davidsona6a78072016-01-11 16:02:17 -0800166 public int roaming;
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900167 /**
168 * Note that this is only populated w/ the default value when read from /proc or written
169 * to disk. We merge in the correct value when reporting this value to clients of
170 * getSummary().
171 */
172 public int defaultNetwork;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100173 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700174 public long rxBytes;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100175 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700176 public long rxPackets;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100177 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700178 public long txBytes;
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100179 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700180 public long txPackets;
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700181 public long operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700182
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100183 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700184 public Entry() {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700185 this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700186 }
187
188 public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700189 this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
190 operations);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700191 }
192
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700193 public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
194 long txBytes, long txPackets, long operations) {
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900195 this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
196 rxBytes, rxPackets, txBytes, txPackets, operations);
197 }
198
Stephen Chen25147872016-10-21 12:44:26 -0700199 public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900200 int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
201 long operations) {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700202 this.iface = iface;
203 this.uid = uid;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700204 this.set = set;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700205 this.tag = tag;
Stephen Chen25147872016-10-21 12:44:26 -0700206 this.metered = metered;
Jeff Davidsona6a78072016-01-11 16:02:17 -0800207 this.roaming = roaming;
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900208 this.defaultNetwork = defaultNetwork;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700209 this.rxBytes = rxBytes;
210 this.rxPackets = rxPackets;
211 this.txBytes = txBytes;
212 this.txPackets = txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700213 this.operations = operations;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700214 }
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700215
Jeff Sharkey63abc372012-01-11 18:38:16 -0800216 public boolean isNegative() {
217 return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
218 }
219
220 public boolean isEmpty() {
221 return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
222 && operations == 0;
223 }
224
Jeff Sharkey70c70532012-05-16 14:51:19 -0700225 public void add(Entry another) {
226 this.rxBytes += another.rxBytes;
227 this.rxPackets += another.rxPackets;
228 this.txBytes += another.txBytes;
229 this.txPackets += another.txPackets;
230 this.operations += another.operations;
231 }
232
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700233 @Override
234 public String toString() {
235 final StringBuilder builder = new StringBuilder();
236 builder.append("iface=").append(iface);
237 builder.append(" uid=").append(uid);
238 builder.append(" set=").append(setToString(set));
239 builder.append(" tag=").append(tagToString(tag));
Stephen Chen25147872016-10-21 12:44:26 -0700240 builder.append(" metered=").append(meteredToString(metered));
Jeff Davidsona6a78072016-01-11 16:02:17 -0800241 builder.append(" roaming=").append(roamingToString(roaming));
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900242 builder.append(" defaultNetwork=").append(defaultNetworkToString(defaultNetwork));
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700243 builder.append(" rxBytes=").append(rxBytes);
244 builder.append(" rxPackets=").append(rxPackets);
245 builder.append(" txBytes=").append(txBytes);
246 builder.append(" txPackets=").append(txPackets);
247 builder.append(" operations=").append(operations);
248 return builder.toString();
249 }
Jeff Sharkey9a2c2a62013-01-14 16:48:51 -0800250
251 @Override
252 public boolean equals(Object o) {
253 if (o instanceof Entry) {
254 final Entry e = (Entry) o;
Stephen Chen25147872016-10-21 12:44:26 -0700255 return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900256 && roaming == e.roaming && defaultNetwork == e.defaultNetwork
257 && rxBytes == e.rxBytes && rxPackets == e.rxPackets
Stephen Chen25147872016-10-21 12:44:26 -0700258 && txBytes == e.txBytes && txPackets == e.txPackets
259 && operations == e.operations && iface.equals(e.iface);
Jeff Sharkey9a2c2a62013-01-14 16:48:51 -0800260 }
261 return false;
262 }
Stephen Chen25147872016-10-21 12:44:26 -0700263
264 @Override
265 public int hashCode() {
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900266 return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface);
Stephen Chen25147872016-10-21 12:44:26 -0700267 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700268 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700269
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100270 @UnsupportedAppUsage
Jeff Sharkey4a971222011-06-11 22:16:55 -0700271 public NetworkStats(long elapsedRealtime, int initialSize) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700272 this.elapsedRealtime = elapsedRealtime;
Jeff Sharkey4a971222011-06-11 22:16:55 -0700273 this.size = 0;
Jeff Sharkeye0c29952018-02-20 17:24:55 -0700274 if (initialSize > 0) {
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800275 this.capacity = initialSize;
276 this.iface = new String[initialSize];
277 this.uid = new int[initialSize];
278 this.set = new int[initialSize];
279 this.tag = new int[initialSize];
Stephen Chen25147872016-10-21 12:44:26 -0700280 this.metered = new int[initialSize];
Jeff Davidsona6a78072016-01-11 16:02:17 -0800281 this.roaming = new int[initialSize];
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900282 this.defaultNetwork = new int[initialSize];
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800283 this.rxBytes = new long[initialSize];
284 this.rxPackets = new long[initialSize];
285 this.txBytes = new long[initialSize];
286 this.txPackets = new long[initialSize];
287 this.operations = new long[initialSize];
288 } else {
289 // Special case for use by NetworkStatsFactory to start out *really* empty.
Jeff Sharkeye0c29952018-02-20 17:24:55 -0700290 clear();
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800291 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700292 }
293
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100294 @UnsupportedAppUsage
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700295 public NetworkStats(Parcel parcel) {
296 elapsedRealtime = parcel.readLong();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700297 size = parcel.readInt();
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800298 capacity = parcel.readInt();
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700299 iface = parcel.createStringArray();
300 uid = parcel.createIntArray();
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700301 set = parcel.createIntArray();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700302 tag = parcel.createIntArray();
Stephen Chen25147872016-10-21 12:44:26 -0700303 metered = parcel.createIntArray();
Jeff Davidsona6a78072016-01-11 16:02:17 -0800304 roaming = parcel.createIntArray();
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900305 defaultNetwork = parcel.createIntArray();
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700306 rxBytes = parcel.createLongArray();
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700307 rxPackets = parcel.createLongArray();
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700308 txBytes = parcel.createLongArray();
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700309 txPackets = parcel.createLongArray();
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700310 operations = parcel.createLongArray();
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700311 }
312
Jeff Sharkeybfdd6802012-04-09 10:49:19 -0700313 @Override
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700314 public void writeToParcel(Parcel dest, int flags) {
315 dest.writeLong(elapsedRealtime);
316 dest.writeInt(size);
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800317 dest.writeInt(capacity);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700318 dest.writeStringArray(iface);
319 dest.writeIntArray(uid);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700320 dest.writeIntArray(set);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700321 dest.writeIntArray(tag);
Stephen Chen25147872016-10-21 12:44:26 -0700322 dest.writeIntArray(metered);
Jeff Davidsona6a78072016-01-11 16:02:17 -0800323 dest.writeIntArray(roaming);
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900324 dest.writeIntArray(defaultNetwork);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700325 dest.writeLongArray(rxBytes);
326 dest.writeLongArray(rxPackets);
327 dest.writeLongArray(txBytes);
328 dest.writeLongArray(txPackets);
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700329 dest.writeLongArray(operations);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700330 }
331
Jeff Sharkey4abb1b82011-11-08 17:35:28 -0800332 @Override
333 public NetworkStats clone() {
334 final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
335 NetworkStats.Entry entry = null;
336 for (int i = 0; i < size; i++) {
337 entry = getValues(i, entry);
338 clone.addValues(entry);
339 }
340 return clone;
341 }
342
Jeff Sharkeye0c29952018-02-20 17:24:55 -0700343 /**
344 * Clear all data stored in this object.
345 */
346 public void clear() {
347 this.capacity = 0;
348 this.iface = EmptyArray.STRING;
349 this.uid = EmptyArray.INT;
350 this.set = EmptyArray.INT;
351 this.tag = EmptyArray.INT;
352 this.metered = EmptyArray.INT;
353 this.roaming = EmptyArray.INT;
354 this.defaultNetwork = EmptyArray.INT;
355 this.rxBytes = EmptyArray.LONG;
356 this.rxPackets = EmptyArray.LONG;
357 this.txBytes = EmptyArray.LONG;
358 this.txPackets = EmptyArray.LONG;
359 this.operations = EmptyArray.LONG;
360 }
361
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800362 @VisibleForTesting
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700363 public NetworkStats addIfaceValues(
364 String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
365 return addValues(
366 iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700367 }
368
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800369 @VisibleForTesting
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700370 public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
371 long rxPackets, long txBytes, long txPackets, long operations) {
372 return addValues(new Entry(
373 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700374 }
375
Jeff Davidsona6a78072016-01-11 16:02:17 -0800376 @VisibleForTesting
Stephen Chen25147872016-10-21 12:44:26 -0700377 public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900378 int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
379 long operations) {
Jeff Davidsona6a78072016-01-11 16:02:17 -0800380 return addValues(new Entry(
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900381 iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
382 txBytes, txPackets, operations));
Jeff Davidsona6a78072016-01-11 16:02:17 -0800383 }
384
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700385 /**
386 * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
387 * object can be recycled across multiple calls.
388 */
389 public NetworkStats addValues(Entry entry) {
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800390 if (size >= capacity) {
391 final int newLength = Math.max(size, 10) * 3 / 2;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700392 iface = Arrays.copyOf(iface, newLength);
393 uid = Arrays.copyOf(uid, newLength);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700394 set = Arrays.copyOf(set, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700395 tag = Arrays.copyOf(tag, newLength);
Stephen Chen25147872016-10-21 12:44:26 -0700396 metered = Arrays.copyOf(metered, newLength);
Jeff Davidsona6a78072016-01-11 16:02:17 -0800397 roaming = Arrays.copyOf(roaming, newLength);
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900398 defaultNetwork = Arrays.copyOf(defaultNetwork, newLength);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700399 rxBytes = Arrays.copyOf(rxBytes, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700400 rxPackets = Arrays.copyOf(rxPackets, newLength);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700401 txBytes = Arrays.copyOf(txBytes, newLength);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700402 txPackets = Arrays.copyOf(txPackets, newLength);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700403 operations = Arrays.copyOf(operations, newLength);
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800404 capacity = newLength;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700405 }
406
Remi NGUYEN VANb6a92012018-03-06 12:36:54 +0900407 setValues(size, entry);
Jeff Sharkey4a971222011-06-11 22:16:55 -0700408 size++;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700409
Jeff Sharkey4a971222011-06-11 22:16:55 -0700410 return this;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700411 }
412
Remi NGUYEN VANb6a92012018-03-06 12:36:54 +0900413 private void setValues(int i, Entry entry) {
414 iface[i] = entry.iface;
415 uid[i] = entry.uid;
416 set[i] = entry.set;
417 tag[i] = entry.tag;
418 metered[i] = entry.metered;
419 roaming[i] = entry.roaming;
420 defaultNetwork[i] = entry.defaultNetwork;
421 rxBytes[i] = entry.rxBytes;
422 rxPackets[i] = entry.rxPackets;
423 txBytes[i] = entry.txBytes;
424 txPackets[i] = entry.txPackets;
425 operations[i] = entry.operations;
426 }
427
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700428 /**
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700429 * Return specific stats entry.
430 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100431 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700432 public Entry getValues(int i, Entry recycle) {
433 final Entry entry = recycle != null ? recycle : new Entry();
434 entry.iface = iface[i];
435 entry.uid = uid[i];
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700436 entry.set = set[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700437 entry.tag = tag[i];
Stephen Chen25147872016-10-21 12:44:26 -0700438 entry.metered = metered[i];
Jeff Davidsona6a78072016-01-11 16:02:17 -0800439 entry.roaming = roaming[i];
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900440 entry.defaultNetwork = defaultNetwork[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700441 entry.rxBytes = rxBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700442 entry.rxPackets = rxPackets[i];
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700443 entry.txBytes = txBytes[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700444 entry.txPackets = txPackets[i];
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700445 entry.operations = operations[i];
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700446 return entry;
447 }
448
junyulai8b8684a2018-10-29 22:26:22 +0800449 /**
450 * If @{code dest} is not equal to @{code src}, copy entry from index @{code src} to index
451 * @{code dest}.
452 */
453 private void maybeCopyEntry(int dest, int src) {
454 if (dest == src) return;
455 iface[dest] = iface[src];
456 uid[dest] = uid[src];
457 set[dest] = set[src];
458 tag[dest] = tag[src];
459 metered[dest] = metered[src];
460 roaming[dest] = roaming[src];
461 defaultNetwork[dest] = defaultNetwork[src];
462 rxBytes[dest] = rxBytes[src];
463 rxPackets[dest] = rxPackets[src];
464 txBytes[dest] = txBytes[src];
465 txPackets[dest] = txPackets[src];
466 operations[dest] = operations[src];
467 }
468
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700469 public long getElapsedRealtime() {
470 return elapsedRealtime;
471 }
472
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800473 public void setElapsedRealtime(long time) {
474 elapsedRealtime = time;
475 }
476
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700477 /**
478 * Return age of this {@link NetworkStats} object with respect to
479 * {@link SystemClock#elapsedRealtime()}.
480 */
481 public long getElapsedRealtimeAge() {
482 return SystemClock.elapsedRealtime() - elapsedRealtime;
483 }
484
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100485 @UnsupportedAppUsage
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700486 public int size() {
487 return size;
488 }
489
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800490 @VisibleForTesting
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700491 public int internalSize() {
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800492 return capacity;
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700493 }
494
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700495 @Deprecated
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700496 public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
Jeff Sharkey63d27a92011-08-03 17:04:22 -0700497 long txBytes, long txPackets, long operations) {
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700498 return combineValues(
Jeff Davidsona6a78072016-01-11 16:02:17 -0800499 iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes,
500 txPackets, operations);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700501 }
502
Jeff Davidsona6a78072016-01-11 16:02:17 -0800503 public NetworkStats combineValues(String iface, int uid, int set, int tag,
504 long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700505 return combineValues(new Entry(
506 iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700507 }
508
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700509 /**
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700510 * Combine given values with an existing row, or create a new row if
Jeff Davidsona6a78072016-01-11 16:02:17 -0800511 * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700512 * also be used to subtract values from existing rows.
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700513 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100514 @UnsupportedAppUsage
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700515 public NetworkStats combineValues(Entry entry) {
Stephen Chen25147872016-10-21 12:44:26 -0700516 final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900517 entry.roaming, entry.defaultNetwork);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700518 if (i == -1) {
519 // only create new entry when positive contribution
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700520 addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700521 } else {
Jeff Sharkeyd37948f2011-07-12 13:57:00 -0700522 rxBytes[i] += entry.rxBytes;
523 rxPackets[i] += entry.rxPackets;
524 txBytes[i] += entry.txBytes;
525 txPackets[i] += entry.txPackets;
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700526 operations[i] += entry.operations;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700527 }
528 return this;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700529 }
530
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700531 /**
Jeff Sharkey905b5892011-09-30 15:19:49 -0700532 * Combine all values from another {@link NetworkStats} into this object.
533 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100534 @UnsupportedAppUsage
Jeff Sharkey905b5892011-09-30 15:19:49 -0700535 public void combineAllValues(NetworkStats another) {
536 NetworkStats.Entry entry = null;
537 for (int i = 0; i < another.size; i++) {
538 entry = another.getValues(i, entry);
539 combineValues(entry);
540 }
541 }
542
543 /**
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700544 * Find first stats index that matches the requested parameters.
545 */
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900546 public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming,
547 int defaultNetwork) {
Jeff Sharkey4a971222011-06-11 22:16:55 -0700548 for (int i = 0; i < size; i++) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700549 if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
Stephen Chen25147872016-10-21 12:44:26 -0700550 && metered == this.metered[i] && roaming == this.roaming[i]
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900551 && defaultNetwork == this.defaultNetwork[i]
Stephen Chen25147872016-10-21 12:44:26 -0700552 && Objects.equals(iface, this.iface[i])) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700553 return i;
554 }
555 }
556 return -1;
557 }
558
559 /**
560 * Find first stats index that matches the requested parameters, starting
561 * search around the hinted index as an optimization.
562 */
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800563 @VisibleForTesting
Stephen Chen25147872016-10-21 12:44:26 -0700564 public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900565 int defaultNetwork, int hintIndex) {
Jeff Sharkey163e6442011-10-31 16:37:52 -0700566 for (int offset = 0; offset < size; offset++) {
567 final int halfOffset = offset / 2;
568
569 // search outwards from hint index, alternating forward and backward
570 final int i;
571 if (offset % 2 == 0) {
572 i = (hintIndex + halfOffset) % size;
573 } else {
574 i = (size + hintIndex - halfOffset - 1) % size;
575 }
576
577 if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i]
Stephen Chen25147872016-10-21 12:44:26 -0700578 && metered == this.metered[i] && roaming == this.roaming[i]
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900579 && defaultNetwork == this.defaultNetwork[i]
Stephen Chen25147872016-10-21 12:44:26 -0700580 && Objects.equals(iface, this.iface[i])) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700581 return i;
582 }
583 }
584 return -1;
585 }
586
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700587 /**
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700588 * Splice in {@link #operations} from the given {@link NetworkStats} based
589 * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
590 * since operation counts are at data layer.
591 */
592 public void spliceOperationsFrom(NetworkStats stats) {
593 for (int i = 0; i < size; i++) {
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900594 final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i],
595 defaultNetwork[i]);
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700596 if (j == -1) {
597 operations[i] = 0;
598 } else {
599 operations[i] = stats.operations[j];
600 }
601 }
602 }
603
604 /**
Jeff Sharkey75279902011-05-24 18:39:45 -0700605 * Return list of unique interfaces known by this data structure.
606 */
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700607 public String[] getUniqueIfaces() {
Jeff Sharkey75279902011-05-24 18:39:45 -0700608 final HashSet<String> ifaces = new HashSet<String>();
609 for (String iface : this.iface) {
610 if (iface != IFACE_ALL) {
611 ifaces.add(iface);
612 }
613 }
614 return ifaces.toArray(new String[ifaces.size()]);
615 }
616
617 /**
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700618 * Return list of unique UIDs known by this data structure.
619 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100620 @UnsupportedAppUsage
Jeff Sharkey61ee0bb2011-05-29 22:50:42 -0700621 public int[] getUniqueUids() {
622 final SparseBooleanArray uids = new SparseBooleanArray();
623 for (int uid : this.uid) {
624 uids.put(uid, true);
625 }
626
627 final int size = uids.size();
628 final int[] result = new int[size];
629 for (int i = 0; i < size; i++) {
630 result[i] = uids.keyAt(i);
631 }
632 return result;
633 }
634
635 /**
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700636 * Return total bytes represented by this snapshot object, usually used when
637 * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
638 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100639 @UnsupportedAppUsage
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700640 public long getTotalBytes() {
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700641 final Entry entry = getTotal(null);
642 return entry.rxBytes + entry.txBytes;
643 }
644
645 /**
646 * Return total of all fields represented by this snapshot object.
647 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100648 @UnsupportedAppUsage
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700649 public Entry getTotal(Entry recycle) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800650 return getTotal(recycle, null, UID_ALL, false);
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700651 }
652
653 /**
654 * Return total of all fields represented by this snapshot object matching
655 * the requested {@link #uid}.
656 */
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100657 @UnsupportedAppUsage
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700658 public Entry getTotal(Entry recycle, int limitUid) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800659 return getTotal(recycle, null, limitUid, false);
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700660 }
661
662 /**
663 * Return total of all fields represented by this snapshot object matching
664 * the requested {@link #iface}.
665 */
666 public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800667 return getTotal(recycle, limitIface, UID_ALL, false);
668 }
669
Mathew Inwoodfa3a7462018-08-08 14:52:47 +0100670 @UnsupportedAppUsage
Jeff Sharkey63abc372012-01-11 18:38:16 -0800671 public Entry getTotalIncludingTags(Entry recycle) {
672 return getTotal(recycle, null, UID_ALL, true);
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700673 }
674
675 /**
676 * Return total of all fields represented by this snapshot object matching
677 * the requested {@link #iface} and {@link #uid}.
678 *
679 * @param limitIface Set of {@link #iface} to include in total; or {@code
680 * null} to include all ifaces.
681 */
Jeff Sharkey63abc372012-01-11 18:38:16 -0800682 private Entry getTotal(
683 Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700684 final Entry entry = recycle != null ? recycle : new Entry();
685
686 entry.iface = IFACE_ALL;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700687 entry.uid = limitUid;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700688 entry.set = SET_ALL;
689 entry.tag = TAG_NONE;
Stephen Chen25147872016-10-21 12:44:26 -0700690 entry.metered = METERED_ALL;
Jeff Davidsona6a78072016-01-11 16:02:17 -0800691 entry.roaming = ROAMING_ALL;
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900692 entry.defaultNetwork = DEFAULT_NETWORK_ALL;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700693 entry.rxBytes = 0;
694 entry.rxPackets = 0;
695 entry.txBytes = 0;
696 entry.txPackets = 0;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700697 entry.operations = 0;
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700698
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700699 for (int i = 0; i < size; i++) {
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700700 final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
701 final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700702
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700703 if (matchesUid && matchesIface) {
704 // skip specific tags, since already counted in TAG_NONE
Jeff Sharkey63abc372012-01-11 18:38:16 -0800705 if (tag[i] != TAG_NONE && !includeTags) continue;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700706
707 entry.rxBytes += rxBytes[i];
708 entry.rxPackets += rxPackets[i];
709 entry.txBytes += txBytes[i];
710 entry.txPackets += txPackets[i];
711 entry.operations += operations[i];
712 }
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700713 }
Jeff Sharkey07b0dd92011-09-01 13:06:19 -0700714 return entry;
Jeff Sharkey8e9992a2011-08-23 18:37:23 -0700715 }
716
717 /**
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800718 * Fast path for battery stats.
719 */
720 public long getTotalPackets() {
721 long total = 0;
722 for (int i = size-1; i >= 0; i--) {
723 total += rxPackets[i] + txPackets[i];
724 }
725 return total;
726 }
727
728 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700729 * Subtract the given {@link NetworkStats}, effectively leaving the delta
730 * between two snapshots in time. Assumes that statistics rows collect over
731 * time, and that none of them have disappeared.
Jeff Sharkey3f391352011-06-05 17:42:53 -0700732 */
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800733 public NetworkStats subtract(NetworkStats right) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800734 return subtract(this, right, null, null);
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800735 }
736
737 /**
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800738 * Subtract the two given {@link NetworkStats} objects, returning the delta
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800739 * between two snapshots in time. Assumes that statistics rows collect over
740 * time, and that none of them have disappeared.
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800741 * <p>
742 * If counters have rolled backwards, they are clamped to {@code 0} and
743 * reported to the given {@link NonMonotonicObserver}.
Jeff Sharkeyd4ef8c8f2011-11-10 17:54:23 -0800744 */
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800745 public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
746 NonMonotonicObserver<C> observer, C cookie) {
747 return subtract(left, right, observer, cookie, null);
748 }
749
750 /**
751 * Subtract the two given {@link NetworkStats} objects, returning the delta
752 * between two snapshots in time. Assumes that statistics rows collect over
753 * time, and that none of them have disappeared.
754 * <p>
755 * If counters have rolled backwards, they are clamped to {@code 0} and
756 * reported to the given {@link NonMonotonicObserver}.
757 * <p>
758 * If <var>recycle</var> is supplied, this NetworkStats object will be
759 * reused (and returned) as the result if it is large enough to contain
760 * the data.
761 */
762 public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
763 NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800764 long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700765 if (deltaRealtime < 0) {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800766 if (observer != null) {
Jeff Sharkey63abc372012-01-11 18:38:16 -0800767 observer.foundNonMonotonic(left, -1, right, -1, cookie);
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800768 }
769 deltaRealtime = 0;
Jeff Sharkey75279902011-05-24 18:39:45 -0700770 }
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700771
Jeff Sharkey75279902011-05-24 18:39:45 -0700772 // result will have our rows, and elapsed time between snapshots
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700773 final Entry entry = new Entry();
Dianne Hackbornd0c5b9a2014-02-21 16:19:05 -0800774 final NetworkStats result;
775 if (recycle != null && recycle.capacity >= left.size) {
776 result = recycle;
777 result.size = 0;
778 result.elapsedRealtime = deltaRealtime;
779 } else {
780 result = new NetworkStats(deltaRealtime, left.size);
781 }
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -0800782 for (int i = 0; i < left.size; i++) {
783 entry.iface = left.iface[i];
784 entry.uid = left.uid[i];
785 entry.set = left.set[i];
786 entry.tag = left.tag[i];
Stephen Chen25147872016-10-21 12:44:26 -0700787 entry.metered = left.metered[i];
Jeff Davidsona6a78072016-01-11 16:02:17 -0800788 entry.roaming = left.roaming[i];
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900789 entry.defaultNetwork = left.defaultNetwork[i];
Hugo Benichiad5e2822017-08-07 15:47:35 +0900790 entry.rxBytes = left.rxBytes[i];
791 entry.rxPackets = left.rxPackets[i];
792 entry.txBytes = left.txBytes[i];
793 entry.txPackets = left.txPackets[i];
794 entry.operations = left.operations[i];
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700795
796 // find remote row that matches, and subtract
Jeff Davidsona6a78072016-01-11 16:02:17 -0800797 final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900798 entry.metered, entry.roaming, entry.defaultNetwork, i);
Hugo Benichiad5e2822017-08-07 15:47:35 +0900799 if (j != -1) {
800 // Found matching row, subtract remote value.
801 entry.rxBytes -= right.rxBytes[j];
802 entry.rxPackets -= right.rxPackets[j];
803 entry.txBytes -= right.txBytes[j];
804 entry.txPackets -= right.txPackets[j];
805 entry.operations -= right.operations[j];
806 }
Jeff Sharkey163e6442011-10-31 16:37:52 -0700807
Hugo Benichiad5e2822017-08-07 15:47:35 +0900808 if (entry.isNegative()) {
809 if (observer != null) {
810 observer.foundNonMonotonic(left, i, right, j, cookie);
Jeff Sharkey3f391352011-06-05 17:42:53 -0700811 }
Hugo Benichiad5e2822017-08-07 15:47:35 +0900812 entry.rxBytes = Math.max(entry.rxBytes, 0);
813 entry.rxPackets = Math.max(entry.rxPackets, 0);
814 entry.txBytes = Math.max(entry.txBytes, 0);
815 entry.txPackets = Math.max(entry.txPackets, 0);
816 entry.operations = Math.max(entry.operations, 0);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700817 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700818
819 result.addValues(entry);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700820 }
821
Jeff Sharkey4a971222011-06-11 22:16:55 -0700822 return result;
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700823 }
824
Jeff Sharkey905b5892011-09-30 15:19:49 -0700825 /**
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900826 * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
827 *
828 * <p>This mutates both base and stacked traffic stats, to account respectively for
829 * double-counted traffic and IPv4/IPv6 header size difference.
830 *
831 * <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
832 * packet on the stacked interface, and once as translated to an IPv6 packet on the
junyulaif6ebf4a2018-10-30 21:49:38 +0800833 * base interface. For correct stats accounting on the base interface, if using xt_qtaguid,
834 * every rx 464xlat packet needs to be subtracted from the root UID on the base interface
835 * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto
836 * clat uid should be ignored.
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900837 *
junyulaic33ac0d2018-10-19 21:14:30 +0800838 * As for eBPF, the per uid stats is collected by different hook, the rx packets on base
junyulaif6ebf4a2018-10-30 21:49:38 +0800839 * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the
840 * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still
841 * needs to be ignored.
junyulaic33ac0d2018-10-19 21:14:30 +0800842 *
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900843 * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only
844 * {@code ConcurrentHashMap}
845 * @param baseTraffic Traffic on the base interfaces. Will be mutated.
846 * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated.
847 * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
junyulaic33ac0d2018-10-19 21:14:30 +0800848 * @param useBpfStats True if eBPF is in use.
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900849 */
850 public static void apply464xlatAdjustments(NetworkStats baseTraffic,
junyulaic33ac0d2018-10-19 21:14:30 +0800851 NetworkStats stackedTraffic, Map<String, String> stackedIfaces, boolean useBpfStats) {
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900852 // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
853 // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
854 final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
855
856 // For recycling
857 Entry entry = null;
858 Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
859
860 for (int i = 0; i < stackedTraffic.size; i++) {
861 entry = stackedTraffic.getValues(i, entry);
862 if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
863 continue;
864 }
865 final String baseIface = stackedIfaces.get(entry.iface);
866 if (baseIface == null) {
867 continue;
868 }
junyulaif6ebf4a2018-10-30 21:49:38 +0800869 // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base
870 // interface. As for eBPF, the per uid stats is collected by different hook, the rx
871 // packets on base interface will not be counted.
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900872 adjust.iface = baseIface;
junyulaic33ac0d2018-10-19 21:14:30 +0800873 if (!useBpfStats) {
874 adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
875 adjust.rxPackets = -entry.rxPackets;
876 }
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900877 adjustments.combineValues(adjust);
878
junyulaic33ac0d2018-10-19 21:14:30 +0800879 // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet
880 // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900881 // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
882 // difference for all packets (http://b/12249687, http:/b/33681750).
883 entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA;
884 entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA;
885 stackedTraffic.setValues(i, entry);
886 }
887
junyulaif6ebf4a2018-10-30 21:49:38 +0800888 // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked
889 // v4 interface, so it needs to be removed to avoid double-counting.
890 baseTraffic.removeUids(new int[] {CLAT_UID});
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900891 baseTraffic.combineAllValues(adjustments);
892 }
893
894 /**
895 * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
896 *
897 * <p>This mutates the object this method is called on. Equivalent to calling
898 * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as
899 * base and stacked traffic.
900 * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
901 */
junyulaic33ac0d2018-10-19 21:14:30 +0800902 public void apply464xlatAdjustments(Map<String, String> stackedIfaces, boolean useBpfStats) {
903 apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats);
Remi NGUYEN VAN75525b32018-02-27 16:47:22 +0900904 }
905
906 /**
Jeff Sharkey905b5892011-09-30 15:19:49 -0700907 * Return total statistics grouped by {@link #iface}; doesn't mutate the
908 * original structure.
909 */
910 public NetworkStats groupedByIface() {
911 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
912
913 final Entry entry = new Entry();
914 entry.uid = UID_ALL;
915 entry.set = SET_ALL;
916 entry.tag = TAG_NONE;
Stephen Chen25147872016-10-21 12:44:26 -0700917 entry.metered = METERED_ALL;
Jeff Davidsona6a78072016-01-11 16:02:17 -0800918 entry.roaming = ROAMING_ALL;
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900919 entry.defaultNetwork = DEFAULT_NETWORK_ALL;
Jeff Sharkey905b5892011-09-30 15:19:49 -0700920 entry.operations = 0L;
921
922 for (int i = 0; i < size; i++) {
923 // skip specific tags, since already counted in TAG_NONE
924 if (tag[i] != TAG_NONE) continue;
925
926 entry.iface = iface[i];
927 entry.rxBytes = rxBytes[i];
928 entry.rxPackets = rxPackets[i];
929 entry.txBytes = txBytes[i];
930 entry.txPackets = txPackets[i];
931 stats.combineValues(entry);
932 }
933
934 return stats;
935 }
936
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700937 /**
938 * Return total statistics grouped by {@link #uid}; doesn't mutate the
939 * original structure.
940 */
941 public NetworkStats groupedByUid() {
942 final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
943
944 final Entry entry = new Entry();
945 entry.iface = IFACE_ALL;
946 entry.set = SET_ALL;
947 entry.tag = TAG_NONE;
Stephen Chen25147872016-10-21 12:44:26 -0700948 entry.metered = METERED_ALL;
Jeff Davidsona6a78072016-01-11 16:02:17 -0800949 entry.roaming = ROAMING_ALL;
Lorenzo Colittiada23ed2018-01-19 01:05:20 +0900950 entry.defaultNetwork = DEFAULT_NETWORK_ALL;
Jeff Sharkey1059c3c2011-10-04 16:54:49 -0700951
952 for (int i = 0; i < size; i++) {
953 // skip specific tags, since already counted in TAG_NONE
954 if (tag[i] != TAG_NONE) continue;
955
956 entry.uid = uid[i];
957 entry.rxBytes = rxBytes[i];
958 entry.rxPackets = rxPackets[i];
959 entry.txBytes = txBytes[i];
960 entry.txPackets = txPackets[i];
961 entry.operations = operations[i];
962 stats.combineValues(entry);
963 }
964
965 return stats;
966 }
967
Jeff Sharkey163e6442011-10-31 16:37:52 -0700968 /**
junyulai8b8684a2018-10-29 22:26:22 +0800969 * Remove all rows that match one of specified UIDs.
Jeff Sharkey163e6442011-10-31 16:37:52 -0700970 */
junyulai8b8684a2018-10-29 22:26:22 +0800971 public void removeUids(int[] uids) {
972 int nextOutputEntry = 0;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700973 for (int i = 0; i < size; i++) {
junyulai8b8684a2018-10-29 22:26:22 +0800974 if (!ArrayUtils.contains(uids, uid[i])) {
975 maybeCopyEntry(nextOutputEntry, i);
976 nextOutputEntry++;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700977 }
978 }
979
junyulai8b8684a2018-10-29 22:26:22 +0800980 size = nextOutputEntry;
Jeff Sharkey163e6442011-10-31 16:37:52 -0700981 }
982
Remi NGUYEN VANb6a92012018-03-06 12:36:54 +0900983 /**
984 * Only keep entries that match all specified filters.
985 *
986 * <p>This mutates the original structure in place. After this method is called,
987 * size is the number of matching entries, and capacity is the previous capacity.
988 * @param limitUid UID to filter for, or {@link #UID_ALL}.
989 * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
990 * @param limitTag Tag to filter for, or {@link #TAG_ALL}.
991 */
992 public void filter(int limitUid, String[] limitIfaces, int limitTag) {
993 if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
994 return;
995 }
996
997 Entry entry = new Entry();
998 int nextOutputEntry = 0;
999 for (int i = 0; i < size; i++) {
1000 entry = getValues(i, entry);
1001 final boolean matches =
1002 (limitUid == UID_ALL || limitUid == entry.uid)
1003 && (limitTag == TAG_ALL || limitTag == entry.tag)
1004 && (limitIfaces == INTERFACES_ALL
1005 || ArrayUtils.contains(limitIfaces, entry.iface));
1006
1007 if (matches) {
1008 setValues(nextOutputEntry, entry);
1009 nextOutputEntry++;
1010 }
1011 }
1012
1013 size = nextOutputEntry;
1014 }
1015
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001016 public void dump(String prefix, PrintWriter pw) {
1017 pw.print(prefix);
1018 pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001019 for (int i = 0; i < size; i++) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001020 pw.print(prefix);
Jeff Sharkey3359aca2011-11-08 18:08:48 -08001021 pw.print(" ["); pw.print(i); pw.print("]");
1022 pw.print(" iface="); pw.print(iface[i]);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001023 pw.print(" uid="); pw.print(uid[i]);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001024 pw.print(" set="); pw.print(setToString(set[i]));
1025 pw.print(" tag="); pw.print(tagToString(tag[i]));
Stephen Chen25147872016-10-21 12:44:26 -07001026 pw.print(" metered="); pw.print(meteredToString(metered[i]));
Jeff Davidsona6a78072016-01-11 16:02:17 -08001027 pw.print(" roaming="); pw.print(roamingToString(roaming[i]));
Lorenzo Colittiada23ed2018-01-19 01:05:20 +09001028 pw.print(" defaultNetwork="); pw.print(defaultNetworkToString(defaultNetwork[i]));
Jeff Sharkeyd37948f2011-07-12 13:57:00 -07001029 pw.print(" rxBytes="); pw.print(rxBytes[i]);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001030 pw.print(" rxPackets="); pw.print(rxPackets[i]);
Jeff Sharkeyd37948f2011-07-12 13:57:00 -07001031 pw.print(" txBytes="); pw.print(txBytes[i]);
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001032 pw.print(" txPackets="); pw.print(txPackets[i]);
1033 pw.print(" operations="); pw.println(operations[i]);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001034 }
1035 }
1036
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001037 /**
1038 * Return text description of {@link #set} value.
1039 */
1040 public static String setToString(int set) {
1041 switch (set) {
1042 case SET_ALL:
1043 return "ALL";
1044 case SET_DEFAULT:
1045 return "DEFAULT";
1046 case SET_FOREGROUND:
1047 return "FOREGROUND";
Wenchao Tong98170b02015-03-17 16:14:23 -07001048 case SET_DBG_VPN_IN:
1049 return "DBG_VPN_IN";
1050 case SET_DBG_VPN_OUT:
1051 return "DBG_VPN_OUT";
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001052 default:
1053 return "UNKNOWN";
1054 }
1055 }
1056
1057 /**
Jeff Sharkey55a442e2014-11-18 18:22:21 -08001058 * Return text description of {@link #set} value.
1059 */
1060 public static String setToCheckinString(int set) {
1061 switch (set) {
1062 case SET_ALL:
1063 return "all";
1064 case SET_DEFAULT:
1065 return "def";
1066 case SET_FOREGROUND:
1067 return "fg";
Wenchao Tong98170b02015-03-17 16:14:23 -07001068 case SET_DBG_VPN_IN:
1069 return "vpnin";
1070 case SET_DBG_VPN_OUT:
1071 return "vpnout";
Jeff Sharkey55a442e2014-11-18 18:22:21 -08001072 default:
1073 return "unk";
1074 }
1075 }
1076
1077 /**
Wenchao Tong98170b02015-03-17 16:14:23 -07001078 * @return true if the querySet matches the dataSet.
1079 */
1080 public static boolean setMatches(int querySet, int dataSet) {
1081 if (querySet == dataSet) {
1082 return true;
1083 }
1084 // SET_ALL matches all non-debugging sets.
1085 return querySet == SET_ALL && dataSet < SET_DEBUG_START;
1086 }
1087
1088 /**
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001089 * Return text description of {@link #tag} value.
1090 */
1091 public static String tagToString(int tag) {
1092 return "0x" + Integer.toHexString(tag);
1093 }
1094
Jeff Davidsona6a78072016-01-11 16:02:17 -08001095 /**
Stephen Chen25147872016-10-21 12:44:26 -07001096 * Return text description of {@link #metered} value.
1097 */
1098 public static String meteredToString(int metered) {
1099 switch (metered) {
1100 case METERED_ALL:
1101 return "ALL";
1102 case METERED_NO:
1103 return "NO";
1104 case METERED_YES:
1105 return "YES";
1106 default:
1107 return "UNKNOWN";
1108 }
1109 }
1110
1111 /**
Jeff Davidsona6a78072016-01-11 16:02:17 -08001112 * Return text description of {@link #roaming} value.
1113 */
1114 public static String roamingToString(int roaming) {
1115 switch (roaming) {
1116 case ROAMING_ALL:
1117 return "ALL";
Jeff Davidson1f7e05e2016-03-10 13:21:38 -08001118 case ROAMING_NO:
1119 return "NO";
1120 case ROAMING_YES:
1121 return "YES";
Jeff Davidsona6a78072016-01-11 16:02:17 -08001122 default:
1123 return "UNKNOWN";
1124 }
1125 }
1126
Lorenzo Colittiada23ed2018-01-19 01:05:20 +09001127 /**
1128 * Return text description of {@link #defaultNetwork} value.
1129 */
1130 public static String defaultNetworkToString(int defaultNetwork) {
1131 switch (defaultNetwork) {
1132 case DEFAULT_NETWORK_ALL:
1133 return "ALL";
1134 case DEFAULT_NETWORK_NO:
1135 return "NO";
1136 case DEFAULT_NETWORK_YES:
1137 return "YES";
1138 default:
1139 return "UNKNOWN";
1140 }
1141 }
1142
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001143 @Override
1144 public String toString() {
1145 final CharArrayWriter writer = new CharArrayWriter();
1146 dump("", new PrintWriter(writer));
1147 return writer.toString();
1148 }
1149
Jeff Sharkeybfdd6802012-04-09 10:49:19 -07001150 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001151 public int describeContents() {
1152 return 0;
1153 }
1154
Mathew Inwoodfa3a7462018-08-08 14:52:47 +01001155 @UnsupportedAppUsage
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001156 public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
Jeff Sharkeybfdd6802012-04-09 10:49:19 -07001157 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001158 public NetworkStats createFromParcel(Parcel in) {
1159 return new NetworkStats(in);
1160 }
1161
Jeff Sharkeybfdd6802012-04-09 10:49:19 -07001162 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001163 public NetworkStats[] newArray(int size) {
1164 return new NetworkStats[size];
1165 }
1166 };
Jeff Sharkey163e6442011-10-31 16:37:52 -07001167
Jeff Sharkey63abc372012-01-11 18:38:16 -08001168 public interface NonMonotonicObserver<C> {
Jeff Sharkey5a7bcf32012-01-10 17:24:44 -08001169 public void foundNonMonotonic(
Jeff Sharkey63abc372012-01-11 18:38:16 -08001170 NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
Jeff Sharkeyb5a97e62018-05-22 11:35:29 -06001171 public void foundNonMonotonic(
1172 NetworkStats stats, int statsIndex, C cookie);
Jeff Sharkey163e6442011-10-31 16:37:52 -07001173 }
Wenchao Tong21377c32015-02-26 18:13:07 -08001174
1175 /**
1176 * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface.
1177 *
1178 * This method should only be called on delta NetworkStats. Do not call this method on a
1179 * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may
1180 * change over time.
1181 *
1182 * This method performs adjustments for one active VPN package and one VPN iface at a time.
1183 *
1184 * It is possible for the VPN software to use multiple underlying networks. This method
1185 * only migrates traffic for the primary underlying network.
1186 *
1187 * @param tunUid uid of the VPN application
1188 * @param tunIface iface of the vpn tunnel
1189 * @param underlyingIface the primary underlying network iface used by the VPN application
1190 * @return true if it successfully adjusts the accounting for VPN, false otherwise
1191 */
1192 public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) {
1193 Entry tunIfaceTotal = new Entry();
1194 Entry underlyingIfaceTotal = new Entry();
1195
1196 tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal);
1197
1198 // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app.
1199 // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression.
1200 // Negative stats should be avoided.
1201 Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal);
1202 if (pool.isEmpty()) {
1203 return true;
1204 }
Jeremy Joslin8b436d82016-08-08 16:07:37 -07001205 Entry moved =
1206 addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool);
Wenchao Tong21377c32015-02-26 18:13:07 -08001207 deductTrafficFromVpnApp(tunUid, underlyingIface, moved);
1208
1209 if (!moved.isEmpty()) {
1210 Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved="
1211 + moved);
1212 return false;
1213 }
1214 return true;
1215 }
1216
1217 /**
1218 * Initializes the data used by the migrateTun() method.
1219 *
1220 * This is the first pass iteration which does the following work:
Jeremy Joslin8b436d82016-08-08 16:07:37 -07001221 * (1) Adds up all the traffic through the tunUid's underlyingIface
Wenchao Tong21377c32015-02-26 18:13:07 -08001222 * (both foreground and background).
Jeremy Joslin8b436d82016-08-08 16:07:37 -07001223 * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself.
Wenchao Tong21377c32015-02-26 18:13:07 -08001224 */
1225 private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface,
1226 Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
1227 Entry recycle = new Entry();
1228 for (int i = 0; i < size; i++) {
1229 getValues(i, recycle);
1230 if (recycle.uid == UID_ALL) {
1231 throw new IllegalStateException(
1232 "Cannot adjust VPN accounting on an iface aggregated NetworkStats.");
Wenchao Tong98170b02015-03-17 16:14:23 -07001233 } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) {
1234 throw new IllegalStateException(
1235 "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*");
Wenchao Tong21377c32015-02-26 18:13:07 -08001236 }
1237
1238 if (recycle.uid == tunUid && recycle.tag == TAG_NONE
1239 && Objects.equals(underlyingIface, recycle.iface)) {
1240 underlyingIfaceTotal.add(recycle);
1241 }
1242
Jeremy Joslin8b436d82016-08-08 16:07:37 -07001243 if (recycle.uid != tunUid && recycle.tag == TAG_NONE
1244 && Objects.equals(tunIface, recycle.iface)) {
1245 // Add up all tunIface traffic excluding traffic from the vpn app itself.
Wenchao Tong21377c32015-02-26 18:13:07 -08001246 tunIfaceTotal.add(recycle);
1247 }
1248 }
1249 }
1250
1251 private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) {
1252 Entry pool = new Entry();
1253 pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes);
1254 pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets);
1255 pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes);
1256 pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets);
1257 pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations);
1258 return pool;
1259 }
1260
Jeremy Joslin8b436d82016-08-08 16:07:37 -07001261 private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface,
Wenchao Tong21377c32015-02-26 18:13:07 -08001262 Entry tunIfaceTotal, Entry pool) {
1263 Entry moved = new Entry();
1264 Entry tmpEntry = new Entry();
1265 tmpEntry.iface = underlyingIface;
1266 for (int i = 0; i < size; i++) {
Jeremy Joslin8b436d82016-08-08 16:07:37 -07001267 // the vpn app is excluded from the redistribution but all moved traffic will be
1268 // deducted from the vpn app (see deductTrafficFromVpnApp below).
1269 if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) {
Wenchao Tong21377c32015-02-26 18:13:07 -08001270 if (tunIfaceTotal.rxBytes > 0) {
1271 tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
1272 } else {
1273 tmpEntry.rxBytes = 0;
1274 }
1275 if (tunIfaceTotal.rxPackets > 0) {
1276 tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets;
1277 } else {
1278 tmpEntry.rxPackets = 0;
1279 }
1280 if (tunIfaceTotal.txBytes > 0) {
1281 tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes;
1282 } else {
1283 tmpEntry.txBytes = 0;
1284 }
1285 if (tunIfaceTotal.txPackets > 0) {
1286 tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets;
1287 } else {
1288 tmpEntry.txPackets = 0;
1289 }
1290 if (tunIfaceTotal.operations > 0) {
1291 tmpEntry.operations =
1292 pool.operations * operations[i] / tunIfaceTotal.operations;
1293 } else {
1294 tmpEntry.operations = 0;
1295 }
1296 tmpEntry.uid = uid[i];
1297 tmpEntry.tag = tag[i];
1298 tmpEntry.set = set[i];
Stephen Chen25147872016-10-21 12:44:26 -07001299 tmpEntry.metered = metered[i];
Jeff Davidsona6a78072016-01-11 16:02:17 -08001300 tmpEntry.roaming = roaming[i];
Lorenzo Colittiada23ed2018-01-19 01:05:20 +09001301 tmpEntry.defaultNetwork = defaultNetwork[i];
Wenchao Tong21377c32015-02-26 18:13:07 -08001302 combineValues(tmpEntry);
1303 if (tag[i] == TAG_NONE) {
1304 moved.add(tmpEntry);
Wenchao Tong98170b02015-03-17 16:14:23 -07001305 // Add debug info
1306 tmpEntry.set = SET_DBG_VPN_IN;
1307 combineValues(tmpEntry);
Wenchao Tong21377c32015-02-26 18:13:07 -08001308 }
1309 }
1310 }
1311 return moved;
1312 }
1313
1314 private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) {
Wenchao Tong98170b02015-03-17 16:14:23 -07001315 // Add debug info
1316 moved.uid = tunUid;
1317 moved.set = SET_DBG_VPN_OUT;
1318 moved.tag = TAG_NONE;
1319 moved.iface = underlyingIface;
Stephen Chen25147872016-10-21 12:44:26 -07001320 moved.metered = METERED_ALL;
Jeff Davidsona6a78072016-01-11 16:02:17 -08001321 moved.roaming = ROAMING_ALL;
Lorenzo Colittiada23ed2018-01-19 01:05:20 +09001322 moved.defaultNetwork = DEFAULT_NETWORK_ALL;
Wenchao Tong98170b02015-03-17 16:14:23 -07001323 combineValues(moved);
1324
Wenchao Tong21377c32015-02-26 18:13:07 -08001325 // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than
1326 // the TAG_NONE traffic.
Jeff Davidsona6a78072016-01-11 16:02:17 -08001327 //
Stephen Chen25147872016-10-21 12:44:26 -07001328 // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO,
1329 // which should be the case as it comes directly from the /proc file. We only blend in the
Jeff Davidsona6a78072016-01-11 16:02:17 -08001330 // roaming data after applying these adjustments, by checking the NetworkIdentity of the
1331 // underlying iface.
1332 int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +09001333 METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
Wenchao Tong21377c32015-02-26 18:13:07 -08001334 if (idxVpnBackground != -1) {
1335 tunSubtract(idxVpnBackground, this, moved);
1336 }
1337
Jeff Davidsona6a78072016-01-11 16:02:17 -08001338 int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE,
Lorenzo Colittiada23ed2018-01-19 01:05:20 +09001339 METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO);
Wenchao Tong21377c32015-02-26 18:13:07 -08001340 if (idxVpnForeground != -1) {
1341 tunSubtract(idxVpnForeground, this, moved);
1342 }
1343 }
1344
1345 private static void tunSubtract(int i, NetworkStats left, Entry right) {
1346 long rxBytes = Math.min(left.rxBytes[i], right.rxBytes);
1347 left.rxBytes[i] -= rxBytes;
1348 right.rxBytes -= rxBytes;
1349
1350 long rxPackets = Math.min(left.rxPackets[i], right.rxPackets);
1351 left.rxPackets[i] -= rxPackets;
1352 right.rxPackets -= rxPackets;
1353
1354 long txBytes = Math.min(left.txBytes[i], right.txBytes);
1355 left.txBytes[i] -= txBytes;
1356 right.txBytes -= txBytes;
1357
1358 long txPackets = Math.min(left.txPackets[i], right.txPackets);
1359 left.txPackets[i] -= txPackets;
1360 right.txPackets -= txPackets;
1361 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001362}