Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package android.net; |
| 18 | |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 19 | import static android.net.NetworkStats.IFACE_ALL; |
Jeff Sharkey | b5d55e3 | 2011-08-10 17:53:27 -0700 | [diff] [blame] | 20 | import static android.net.NetworkStats.SET_DEFAULT; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 21 | import static android.net.NetworkStats.TAG_NONE; |
| 22 | import static android.net.NetworkStats.UID_ALL; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 23 | import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray; |
| 24 | import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray; |
| 25 | import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; |
| 26 | import static android.net.NetworkStatsHistory.Entry.UNKNOWN; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 27 | import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 28 | import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; |
Jeff Sharkey | 55a442e | 2014-11-18 18:22:21 -0800 | [diff] [blame] | 29 | import static android.text.format.DateUtils.SECOND_IN_MILLIS; |
Jeff Sharkey | f4de294 | 2017-08-29 15:32:13 -0600 | [diff] [blame] | 30 | |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 31 | import static com.android.internal.util.ArrayUtils.total; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 32 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 33 | import android.annotation.UnsupportedAppUsage; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 34 | import android.os.Parcel; |
| 35 | import android.os.Parcelable; |
Makoto Onuki | da65a52 | 2017-01-13 10:23:30 -0800 | [diff] [blame] | 36 | import android.service.NetworkStatsHistoryBucketProto; |
| 37 | import android.service.NetworkStatsHistoryProto; |
Jeff Sharkey | 69b0f63 | 2011-09-11 17:33:14 -0700 | [diff] [blame] | 38 | import android.util.MathUtils; |
Makoto Onuki | da65a52 | 2017-01-13 10:23:30 -0800 | [diff] [blame] | 39 | import android.util.proto.ProtoOutputStream; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 40 | |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 41 | import com.android.internal.util.IndentingPrintWriter; |
| 42 | |
Jeff Sharkey | e0c2995 | 2018-02-20 17:24:55 -0700 | [diff] [blame] | 43 | import libcore.util.EmptyArray; |
| 44 | |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 45 | import java.io.CharArrayWriter; |
| 46 | import java.io.DataInputStream; |
| 47 | import java.io.DataOutputStream; |
| 48 | import java.io.IOException; |
Jeff Sharkey | 55a442e | 2014-11-18 18:22:21 -0800 | [diff] [blame] | 49 | import java.io.PrintWriter; |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 50 | import java.net.ProtocolException; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 51 | import java.util.Arrays; |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 52 | import java.util.Random; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 53 | |
| 54 | /** |
| 55 | * Collection of historical network statistics, recorded into equally-sized |
| 56 | * "buckets" in time. Internally it stores data in {@code long} series for more |
| 57 | * efficient persistence. |
| 58 | * <p> |
| 59 | * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for |
| 60 | * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is |
| 61 | * sorted at all times. |
| 62 | * |
| 63 | * @hide |
| 64 | */ |
| 65 | public class NetworkStatsHistory implements Parcelable { |
Jeff Sharkey | 1b5a2a9 | 2011-06-18 18:34:16 -0700 | [diff] [blame] | 66 | private static final int VERSION_INIT = 1; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 67 | private static final int VERSION_ADD_PACKETS = 2; |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 68 | private static final int VERSION_ADD_ACTIVE = 3; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 69 | |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 70 | public static final int FIELD_ACTIVE_TIME = 0x01; |
| 71 | public static final int FIELD_RX_BYTES = 0x02; |
| 72 | public static final int FIELD_RX_PACKETS = 0x04; |
| 73 | public static final int FIELD_TX_BYTES = 0x08; |
| 74 | public static final int FIELD_TX_PACKETS = 0x10; |
| 75 | public static final int FIELD_OPERATIONS = 0x20; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 76 | |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 77 | public static final int FIELD_ALL = 0xFFFFFFFF; |
| 78 | |
| 79 | private long bucketDuration; |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 80 | private int bucketCount; |
| 81 | private long[] bucketStart; |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 82 | private long[] activeTime; |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 83 | private long[] rxBytes; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 84 | private long[] rxPackets; |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 85 | private long[] txBytes; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 86 | private long[] txPackets; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 87 | private long[] operations; |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 88 | private long totalBytes; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 89 | |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 90 | public static class Entry { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 91 | public static final long UNKNOWN = -1; |
| 92 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 93 | @UnsupportedAppUsage |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 94 | public long bucketDuration; |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 95 | @UnsupportedAppUsage |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 96 | public long bucketStart; |
| 97 | public long activeTime; |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 98 | @UnsupportedAppUsage |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 99 | public long rxBytes; |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 100 | @UnsupportedAppUsage |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 101 | public long rxPackets; |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 102 | @UnsupportedAppUsage |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 103 | public long txBytes; |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 104 | @UnsupportedAppUsage |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 105 | public long txPackets; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 106 | public long operations; |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 107 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 108 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 109 | @UnsupportedAppUsage |
Jeff Sharkey | d2a4587 | 2011-05-28 20:56:34 -0700 | [diff] [blame] | 110 | public NetworkStatsHistory(long bucketDuration) { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 111 | this(bucketDuration, 10, FIELD_ALL); |
Jeff Sharkey | 4a97122 | 2011-06-11 22:16:55 -0700 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | public NetworkStatsHistory(long bucketDuration, int initialSize) { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 115 | this(bucketDuration, initialSize, FIELD_ALL); |
| 116 | } |
| 117 | |
| 118 | public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) { |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 119 | this.bucketDuration = bucketDuration; |
Jeff Sharkey | 4a97122 | 2011-06-11 22:16:55 -0700 | [diff] [blame] | 120 | bucketStart = new long[initialSize]; |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 121 | if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize]; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 122 | if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize]; |
| 123 | if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize]; |
| 124 | if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize]; |
| 125 | if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize]; |
| 126 | if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize]; |
Jeff Sharkey | 4a97122 | 2011-06-11 22:16:55 -0700 | [diff] [blame] | 127 | bucketCount = 0; |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 128 | totalBytes = 0; |
| 129 | } |
| 130 | |
| 131 | public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) { |
| 132 | this(bucketDuration, existing.estimateResizeBuckets(bucketDuration)); |
| 133 | recordEntireHistory(existing); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 134 | } |
| 135 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 136 | @UnsupportedAppUsage |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 137 | public NetworkStatsHistory(Parcel in) { |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 138 | bucketDuration = in.readLong(); |
| 139 | bucketStart = readLongArray(in); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 140 | activeTime = readLongArray(in); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 141 | rxBytes = readLongArray(in); |
| 142 | rxPackets = readLongArray(in); |
| 143 | txBytes = readLongArray(in); |
| 144 | txPackets = readLongArray(in); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 145 | operations = readLongArray(in); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 146 | bucketCount = bucketStart.length; |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 147 | totalBytes = in.readLong(); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 148 | } |
| 149 | |
Jeff Sharkey | bfdd680 | 2012-04-09 10:49:19 -0700 | [diff] [blame] | 150 | @Override |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 151 | public void writeToParcel(Parcel out, int flags) { |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 152 | out.writeLong(bucketDuration); |
| 153 | writeLongArray(out, bucketStart, bucketCount); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 154 | writeLongArray(out, activeTime, bucketCount); |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 155 | writeLongArray(out, rxBytes, bucketCount); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 156 | writeLongArray(out, rxPackets, bucketCount); |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 157 | writeLongArray(out, txBytes, bucketCount); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 158 | writeLongArray(out, txPackets, bucketCount); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 159 | writeLongArray(out, operations, bucketCount); |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 160 | out.writeLong(totalBytes); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | public NetworkStatsHistory(DataInputStream in) throws IOException { |
| 164 | final int version = in.readInt(); |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 165 | switch (version) { |
Jeff Sharkey | 1b5a2a9 | 2011-06-18 18:34:16 -0700 | [diff] [blame] | 166 | case VERSION_INIT: { |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 167 | bucketDuration = in.readLong(); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 168 | bucketStart = readFullLongArray(in); |
| 169 | rxBytes = readFullLongArray(in); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 170 | rxPackets = new long[bucketStart.length]; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 171 | txBytes = readFullLongArray(in); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 172 | txPackets = new long[bucketStart.length]; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 173 | operations = new long[bucketStart.length]; |
| 174 | bucketCount = bucketStart.length; |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 175 | totalBytes = total(rxBytes) + total(txBytes); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 176 | break; |
| 177 | } |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 178 | case VERSION_ADD_PACKETS: |
| 179 | case VERSION_ADD_ACTIVE: { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 180 | bucketDuration = in.readLong(); |
| 181 | bucketStart = readVarLongArray(in); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 182 | activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in) |
| 183 | : new long[bucketStart.length]; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 184 | rxBytes = readVarLongArray(in); |
| 185 | rxPackets = readVarLongArray(in); |
| 186 | txBytes = readVarLongArray(in); |
| 187 | txPackets = readVarLongArray(in); |
| 188 | operations = readVarLongArray(in); |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 189 | bucketCount = bucketStart.length; |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 190 | totalBytes = total(rxBytes) + total(txBytes); |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 191 | break; |
| 192 | } |
| 193 | default: { |
| 194 | throw new ProtocolException("unexpected version: " + version); |
| 195 | } |
| 196 | } |
Jeff Sharkey | b0a579f | 2012-11-02 14:48:20 -0700 | [diff] [blame] | 197 | |
| 198 | if (bucketStart.length != bucketCount || rxBytes.length != bucketCount |
| 199 | || rxPackets.length != bucketCount || txBytes.length != bucketCount |
| 200 | || txPackets.length != bucketCount || operations.length != bucketCount) { |
| 201 | throw new ProtocolException("Mismatched history lengths"); |
| 202 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | public void writeToStream(DataOutputStream out) throws IOException { |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 206 | out.writeInt(VERSION_ADD_ACTIVE); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 207 | out.writeLong(bucketDuration); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 208 | writeVarLongArray(out, bucketStart, bucketCount); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 209 | writeVarLongArray(out, activeTime, bucketCount); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 210 | writeVarLongArray(out, rxBytes, bucketCount); |
| 211 | writeVarLongArray(out, rxPackets, bucketCount); |
| 212 | writeVarLongArray(out, txBytes, bucketCount); |
| 213 | writeVarLongArray(out, txPackets, bucketCount); |
| 214 | writeVarLongArray(out, operations, bucketCount); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 215 | } |
| 216 | |
Jeff Sharkey | bfdd680 | 2012-04-09 10:49:19 -0700 | [diff] [blame] | 217 | @Override |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 218 | public int describeContents() { |
| 219 | return 0; |
| 220 | } |
| 221 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 222 | @UnsupportedAppUsage |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 223 | public int size() { |
| 224 | return bucketCount; |
| 225 | } |
| 226 | |
| 227 | public long getBucketDuration() { |
| 228 | return bucketDuration; |
| 229 | } |
| 230 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 231 | @UnsupportedAppUsage |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 232 | public long getStart() { |
| 233 | if (bucketCount > 0) { |
| 234 | return bucketStart[0]; |
| 235 | } else { |
| 236 | return Long.MAX_VALUE; |
| 237 | } |
| 238 | } |
| 239 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 240 | @UnsupportedAppUsage |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 241 | public long getEnd() { |
| 242 | if (bucketCount > 0) { |
| 243 | return bucketStart[bucketCount - 1] + bucketDuration; |
| 244 | } else { |
| 245 | return Long.MIN_VALUE; |
| 246 | } |
| 247 | } |
| 248 | |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 249 | /** |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 250 | * Return total bytes represented by this history. |
| 251 | */ |
| 252 | public long getTotalBytes() { |
| 253 | return totalBytes; |
| 254 | } |
| 255 | |
| 256 | /** |
Jeff Sharkey | 69b0f63 | 2011-09-11 17:33:14 -0700 | [diff] [blame] | 257 | * Return index of bucket that contains or is immediately before the |
| 258 | * requested time. |
| 259 | */ |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 260 | @UnsupportedAppUsage |
Jeff Sharkey | 69b0f63 | 2011-09-11 17:33:14 -0700 | [diff] [blame] | 261 | public int getIndexBefore(long time) { |
| 262 | int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); |
| 263 | if (index < 0) { |
| 264 | index = (~index) - 1; |
| 265 | } else { |
| 266 | index -= 1; |
| 267 | } |
| 268 | return MathUtils.constrain(index, 0, bucketCount - 1); |
| 269 | } |
| 270 | |
| 271 | /** |
| 272 | * Return index of bucket that contains or is immediately after the |
| 273 | * requested time. |
| 274 | */ |
| 275 | public int getIndexAfter(long time) { |
| 276 | int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); |
| 277 | if (index < 0) { |
| 278 | index = ~index; |
| 279 | } else { |
| 280 | index += 1; |
| 281 | } |
| 282 | return MathUtils.constrain(index, 0, bucketCount - 1); |
| 283 | } |
| 284 | |
| 285 | /** |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 286 | * Return specific stats entry. |
| 287 | */ |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 288 | @UnsupportedAppUsage |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 289 | public Entry getValues(int i, Entry recycle) { |
| 290 | final Entry entry = recycle != null ? recycle : new Entry(); |
| 291 | entry.bucketStart = bucketStart[i]; |
| 292 | entry.bucketDuration = bucketDuration; |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 293 | entry.activeTime = getLong(activeTime, i, UNKNOWN); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 294 | entry.rxBytes = getLong(rxBytes, i, UNKNOWN); |
| 295 | entry.rxPackets = getLong(rxPackets, i, UNKNOWN); |
| 296 | entry.txBytes = getLong(txBytes, i, UNKNOWN); |
| 297 | entry.txPackets = getLong(txPackets, i, UNKNOWN); |
| 298 | entry.operations = getLong(operations, i, UNKNOWN); |
Jeff Sharkey | d37948f | 2011-07-12 13:57:00 -0700 | [diff] [blame] | 299 | return entry; |
| 300 | } |
| 301 | |
Jeff Sharkey | f4de294 | 2017-08-29 15:32:13 -0600 | [diff] [blame] | 302 | public void setValues(int i, Entry entry) { |
| 303 | // Unwind old values |
| 304 | if (rxBytes != null) totalBytes -= rxBytes[i]; |
| 305 | if (txBytes != null) totalBytes -= txBytes[i]; |
| 306 | |
| 307 | bucketStart[i] = entry.bucketStart; |
| 308 | setLong(activeTime, i, entry.activeTime); |
| 309 | setLong(rxBytes, i, entry.rxBytes); |
| 310 | setLong(rxPackets, i, entry.rxPackets); |
| 311 | setLong(txBytes, i, entry.txBytes); |
| 312 | setLong(txPackets, i, entry.txPackets); |
| 313 | setLong(operations, i, entry.operations); |
| 314 | |
| 315 | // Apply new values |
| 316 | if (rxBytes != null) totalBytes += rxBytes[i]; |
| 317 | if (txBytes != null) totalBytes += txBytes[i]; |
| 318 | } |
| 319 | |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 320 | /** |
| 321 | * Record that data traffic occurred in the given time range. Will |
| 322 | * distribute across internal buckets, creating new buckets as needed. |
| 323 | */ |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 324 | @Deprecated |
| 325 | public void recordData(long start, long end, long rxBytes, long txBytes) { |
Jeff Sharkey | b5d55e3 | 2011-08-10 17:53:27 -0700 | [diff] [blame] | 326 | recordData(start, end, new NetworkStats.Entry( |
| 327 | IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L)); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Record that data traffic occurred in the given time range. Will |
| 332 | * distribute across internal buckets, creating new buckets as needed. |
| 333 | */ |
| 334 | public void recordData(long start, long end, NetworkStats.Entry entry) { |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 335 | long rxBytes = entry.rxBytes; |
| 336 | long rxPackets = entry.rxPackets; |
| 337 | long txBytes = entry.txBytes; |
| 338 | long txPackets = entry.txPackets; |
| 339 | long operations = entry.operations; |
| 340 | |
| 341 | if (entry.isNegative()) { |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 342 | throw new IllegalArgumentException("tried recording negative data"); |
Jeff Sharkey | 1b5a2a9 | 2011-06-18 18:34:16 -0700 | [diff] [blame] | 343 | } |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 344 | if (entry.isEmpty()) { |
Jeff Sharkey | 367d15a | 2011-09-22 14:59:51 -0700 | [diff] [blame] | 345 | return; |
| 346 | } |
Jeff Sharkey | 1b5a2a9 | 2011-06-18 18:34:16 -0700 | [diff] [blame] | 347 | |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 348 | // create any buckets needed by this range |
| 349 | ensureBuckets(start, end); |
| 350 | |
| 351 | // distribute data usage into buckets |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 352 | long duration = end - start; |
Jeff Sharkey | 69b0f63 | 2011-09-11 17:33:14 -0700 | [diff] [blame] | 353 | final int startIndex = getIndexAfter(end); |
| 354 | for (int i = startIndex; i >= 0; i--) { |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 355 | final long curStart = bucketStart[i]; |
| 356 | final long curEnd = curStart + bucketDuration; |
| 357 | |
| 358 | // bucket is older than record; we're finished |
| 359 | if (curEnd < start) break; |
| 360 | // bucket is newer than record; keep looking |
| 361 | if (curStart > end) continue; |
| 362 | |
| 363 | final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 364 | if (overlap <= 0) continue; |
| 365 | |
| 366 | // integer math each time is faster than floating point |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 367 | final long fracRxBytes = rxBytes * overlap / duration; |
| 368 | final long fracRxPackets = rxPackets * overlap / duration; |
| 369 | final long fracTxBytes = txBytes * overlap / duration; |
| 370 | final long fracTxPackets = txPackets * overlap / duration; |
| 371 | final long fracOperations = operations * overlap / duration; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 372 | |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 373 | addLong(activeTime, i, overlap); |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 374 | addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes; |
| 375 | addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets; |
| 376 | addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes; |
| 377 | addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets; |
| 378 | addLong(this.operations, i, fracOperations); operations -= fracOperations; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 379 | |
| 380 | duration -= overlap; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 381 | } |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 382 | |
| 383 | totalBytes += entry.rxBytes + entry.txBytes; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 384 | } |
| 385 | |
| 386 | /** |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 387 | * Record an entire {@link NetworkStatsHistory} into this history. Usually |
| 388 | * for combining together stats for external reporting. |
| 389 | */ |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 390 | @UnsupportedAppUsage |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 391 | public void recordEntireHistory(NetworkStatsHistory input) { |
Jeff Sharkey | 70c7053 | 2012-05-16 14:51:19 -0700 | [diff] [blame] | 392 | recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE); |
| 393 | } |
| 394 | |
| 395 | /** |
| 396 | * Record given {@link NetworkStatsHistory} into this history, copying only |
| 397 | * buckets that atomically occur in the inclusive time range. Doesn't |
| 398 | * interpolate across partial buckets. |
| 399 | */ |
| 400 | public void recordHistory(NetworkStatsHistory input, long start, long end) { |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 401 | final NetworkStats.Entry entry = new NetworkStats.Entry( |
Jeff Sharkey | b5d55e3 | 2011-08-10 17:53:27 -0700 | [diff] [blame] | 402 | IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 403 | for (int i = 0; i < input.bucketCount; i++) { |
Jeff Sharkey | 70c7053 | 2012-05-16 14:51:19 -0700 | [diff] [blame] | 404 | final long bucketStart = input.bucketStart[i]; |
| 405 | final long bucketEnd = bucketStart + input.bucketDuration; |
| 406 | |
| 407 | // skip when bucket is outside requested range |
| 408 | if (bucketStart < start || bucketEnd > end) continue; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 409 | |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 410 | entry.rxBytes = getLong(input.rxBytes, i, 0L); |
| 411 | entry.rxPackets = getLong(input.rxPackets, i, 0L); |
| 412 | entry.txBytes = getLong(input.txBytes, i, 0L); |
| 413 | entry.txPackets = getLong(input.txPackets, i, 0L); |
| 414 | entry.operations = getLong(input.operations, i, 0L); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 415 | |
Jeff Sharkey | 70c7053 | 2012-05-16 14:51:19 -0700 | [diff] [blame] | 416 | recordData(bucketStart, bucketEnd, entry); |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 417 | } |
| 418 | } |
| 419 | |
| 420 | /** |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 421 | * Ensure that buckets exist for given time range, creating as needed. |
| 422 | */ |
| 423 | private void ensureBuckets(long start, long end) { |
| 424 | // normalize incoming range to bucket boundaries |
| 425 | start -= start % bucketDuration; |
| 426 | end += (bucketDuration - (end % bucketDuration)) % bucketDuration; |
| 427 | |
| 428 | for (long now = start; now < end; now += bucketDuration) { |
| 429 | // try finding existing bucket |
| 430 | final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); |
| 431 | if (index < 0) { |
| 432 | // bucket missing, create and insert |
| 433 | insertBucket(~index, now); |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | /** |
| 439 | * Insert new bucket at requested index and starting time. |
| 440 | */ |
| 441 | private void insertBucket(int index, long start) { |
| 442 | // create more buckets when needed |
Jeff Sharkey | 4a97122 | 2011-06-11 22:16:55 -0700 | [diff] [blame] | 443 | if (bucketCount >= bucketStart.length) { |
| 444 | final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 445 | bucketStart = Arrays.copyOf(bucketStart, newLength); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 446 | if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 447 | if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength); |
| 448 | if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength); |
| 449 | if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength); |
| 450 | if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength); |
| 451 | if (operations != null) operations = Arrays.copyOf(operations, newLength); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 452 | } |
| 453 | |
| 454 | // create gap when inserting bucket in middle |
| 455 | if (index < bucketCount) { |
| 456 | final int dstPos = index + 1; |
| 457 | final int length = bucketCount - index; |
| 458 | |
| 459 | System.arraycopy(bucketStart, index, bucketStart, dstPos, length); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 460 | if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 461 | if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length); |
| 462 | if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length); |
| 463 | if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length); |
| 464 | if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length); |
| 465 | if (operations != null) System.arraycopy(operations, index, operations, dstPos, length); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 466 | } |
| 467 | |
| 468 | bucketStart[index] = start; |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 469 | setLong(activeTime, index, 0L); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 470 | setLong(rxBytes, index, 0L); |
| 471 | setLong(rxPackets, index, 0L); |
| 472 | setLong(txBytes, index, 0L); |
| 473 | setLong(txPackets, index, 0L); |
| 474 | setLong(operations, index, 0L); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 475 | bucketCount++; |
| 476 | } |
| 477 | |
| 478 | /** |
Jeff Sharkey | e0c2995 | 2018-02-20 17:24:55 -0700 | [diff] [blame] | 479 | * Clear all data stored in this object. |
| 480 | */ |
| 481 | public void clear() { |
| 482 | bucketStart = EmptyArray.LONG; |
| 483 | if (activeTime != null) activeTime = EmptyArray.LONG; |
| 484 | if (rxBytes != null) rxBytes = EmptyArray.LONG; |
| 485 | if (rxPackets != null) rxPackets = EmptyArray.LONG; |
| 486 | if (txBytes != null) txBytes = EmptyArray.LONG; |
| 487 | if (txPackets != null) txPackets = EmptyArray.LONG; |
| 488 | if (operations != null) operations = EmptyArray.LONG; |
| 489 | bucketCount = 0; |
| 490 | totalBytes = 0; |
| 491 | } |
| 492 | |
| 493 | /** |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 494 | * Remove buckets older than requested cutoff. |
| 495 | */ |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 496 | @Deprecated |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 497 | public void removeBucketsBefore(long cutoff) { |
| 498 | int i; |
| 499 | for (i = 0; i < bucketCount; i++) { |
| 500 | final long curStart = bucketStart[i]; |
| 501 | final long curEnd = curStart + bucketDuration; |
| 502 | |
| 503 | // cutoff happens before or during this bucket; everything before |
| 504 | // this bucket should be removed. |
| 505 | if (curEnd > cutoff) break; |
| 506 | } |
| 507 | |
| 508 | if (i > 0) { |
| 509 | final int length = bucketStart.length; |
| 510 | bucketStart = Arrays.copyOfRange(bucketStart, i, length); |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 511 | if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 512 | if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length); |
| 513 | if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length); |
| 514 | if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length); |
| 515 | if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length); |
| 516 | if (operations != null) operations = Arrays.copyOfRange(operations, i, length); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 517 | bucketCount -= i; |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 518 | |
| 519 | // TODO: subtract removed values from totalBytes |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 520 | } |
| 521 | } |
| 522 | |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 523 | /** |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 524 | * Return interpolated data usage across the requested range. Interpolates |
| 525 | * across buckets, so values may be rounded slightly. |
| 526 | */ |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 527 | @UnsupportedAppUsage |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 528 | public Entry getValues(long start, long end, Entry recycle) { |
| 529 | return getValues(start, end, Long.MAX_VALUE, recycle); |
| 530 | } |
| 531 | |
| 532 | /** |
| 533 | * Return interpolated data usage across the requested range. Interpolates |
| 534 | * across buckets, so values may be rounded slightly. |
| 535 | */ |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 536 | @UnsupportedAppUsage |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 537 | public Entry getValues(long start, long end, long now, Entry recycle) { |
| 538 | final Entry entry = recycle != null ? recycle : new Entry(); |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 539 | entry.bucketDuration = end - start; |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 540 | entry.bucketStart = start; |
| 541 | entry.activeTime = activeTime != null ? 0 : UNKNOWN; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 542 | entry.rxBytes = rxBytes != null ? 0 : UNKNOWN; |
| 543 | entry.rxPackets = rxPackets != null ? 0 : UNKNOWN; |
| 544 | entry.txBytes = txBytes != null ? 0 : UNKNOWN; |
| 545 | entry.txPackets = txPackets != null ? 0 : UNKNOWN; |
| 546 | entry.operations = operations != null ? 0 : UNKNOWN; |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 547 | |
Jeff Sharkey | 69b0f63 | 2011-09-11 17:33:14 -0700 | [diff] [blame] | 548 | final int startIndex = getIndexAfter(end); |
| 549 | for (int i = startIndex; i >= 0; i--) { |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 550 | final long curStart = bucketStart[i]; |
| 551 | final long curEnd = curStart + bucketDuration; |
| 552 | |
Jeff Sharkey | 34c73ac | 2011-09-18 13:30:23 -0700 | [diff] [blame] | 553 | // bucket is older than request; we're finished |
| 554 | if (curEnd <= start) break; |
| 555 | // bucket is newer than request; keep looking |
| 556 | if (curStart >= end) continue; |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 557 | |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 558 | // include full value for active buckets, otherwise only fractional |
| 559 | final boolean activeBucket = curStart < now && curEnd > now; |
Jeff Sharkey | 69b0f63 | 2011-09-11 17:33:14 -0700 | [diff] [blame] | 560 | final long overlap; |
| 561 | if (activeBucket) { |
| 562 | overlap = bucketDuration; |
| 563 | } else { |
| 564 | final long overlapEnd = curEnd < end ? curEnd : end; |
| 565 | final long overlapStart = curStart > start ? curStart : start; |
| 566 | overlap = overlapEnd - overlapStart; |
| 567 | } |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 568 | if (overlap <= 0) continue; |
| 569 | |
| 570 | // integer math each time is faster than floating point |
Jeff Sharkey | 558a232 | 2011-08-24 15:42:09 -0700 | [diff] [blame] | 571 | if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration; |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 572 | if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration; |
| 573 | if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration; |
| 574 | if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration; |
| 575 | if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; |
| 576 | if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 577 | } |
Jeff Sharkey | 434962e | 2011-07-12 20:20:56 -0700 | [diff] [blame] | 578 | return entry; |
Jeff Sharkey | 19862bf | 2011-06-02 17:38:22 -0700 | [diff] [blame] | 579 | } |
| 580 | |
| 581 | /** |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 582 | * @deprecated only for temporary testing |
| 583 | */ |
| 584 | @Deprecated |
Jeff Sharkey | 293779f | 2011-10-05 23:31:57 -0700 | [diff] [blame] | 585 | public void generateRandom(long start, long end, long bytes) { |
| 586 | final Random r = new Random(); |
| 587 | |
| 588 | final float fractionRx = r.nextFloat(); |
| 589 | final long rxBytes = (long) (bytes * fractionRx); |
| 590 | final long txBytes = (long) (bytes * (1 - fractionRx)); |
| 591 | |
| 592 | final long rxPackets = rxBytes / 1024; |
| 593 | final long txPackets = txBytes / 1024; |
| 594 | final long operations = rxBytes / 2048; |
| 595 | |
| 596 | generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r); |
| 597 | } |
| 598 | |
| 599 | /** |
| 600 | * @deprecated only for temporary testing |
| 601 | */ |
| 602 | @Deprecated |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 603 | public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes, |
Jeff Sharkey | 293779f | 2011-10-05 23:31:57 -0700 | [diff] [blame] | 604 | long txPackets, long operations, Random r) { |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 605 | ensureBuckets(start, end); |
| 606 | |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 607 | final NetworkStats.Entry entry = new NetworkStats.Entry( |
Jeff Sharkey | b5d55e3 | 2011-08-10 17:53:27 -0700 | [diff] [blame] | 608 | IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); |
Jeff Sharkey | 04cd0e4 | 2011-08-05 11:09:46 -0700 | [diff] [blame] | 609 | while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128 |
| 610 | || operations > 32) { |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 611 | final long curStart = randomLong(r, start, end); |
Jeff Sharkey | 293779f | 2011-10-05 23:31:57 -0700 | [diff] [blame] | 612 | final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 613 | |
| 614 | entry.rxBytes = randomLong(r, 0, rxBytes); |
| 615 | entry.rxPackets = randomLong(r, 0, rxPackets); |
| 616 | entry.txBytes = randomLong(r, 0, txBytes); |
| 617 | entry.txPackets = randomLong(r, 0, txPackets); |
| 618 | entry.operations = randomLong(r, 0, operations); |
| 619 | |
| 620 | rxBytes -= entry.rxBytes; |
| 621 | rxPackets -= entry.rxPackets; |
| 622 | txBytes -= entry.txBytes; |
| 623 | txPackets -= entry.txPackets; |
| 624 | operations -= entry.operations; |
Jeff Sharkey | f0ceede | 2011-08-02 17:22:34 -0700 | [diff] [blame] | 625 | |
| 626 | recordData(curStart, curEnd, entry); |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 627 | } |
| 628 | } |
| 629 | |
Jeff Sharkey | 293779f | 2011-10-05 23:31:57 -0700 | [diff] [blame] | 630 | public static long randomLong(Random r, long start, long end) { |
Jeff Sharkey | 61ee0bb | 2011-05-29 22:50:42 -0700 | [diff] [blame] | 631 | return (long) (start + (r.nextFloat() * (end - start))); |
| 632 | } |
| 633 | |
Jeff Sharkey | 55a442e | 2014-11-18 18:22:21 -0800 | [diff] [blame] | 634 | /** |
| 635 | * Quickly determine if this history intersects with given window. |
| 636 | */ |
| 637 | public boolean intersects(long start, long end) { |
| 638 | final long dataStart = getStart(); |
| 639 | final long dataEnd = getEnd(); |
| 640 | if (start >= dataStart && start <= dataEnd) return true; |
| 641 | if (end >= dataStart && end <= dataEnd) return true; |
| 642 | if (dataStart >= start && dataStart <= end) return true; |
| 643 | if (dataEnd >= start && dataEnd <= end) return true; |
| 644 | return false; |
| 645 | } |
| 646 | |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 647 | public void dump(IndentingPrintWriter pw, boolean fullHistory) { |
Jeff Sharkey | 55a442e | 2014-11-18 18:22:21 -0800 | [diff] [blame] | 648 | pw.print("NetworkStatsHistory: bucketDuration="); |
| 649 | pw.println(bucketDuration / SECOND_IN_MILLIS); |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 650 | pw.increaseIndent(); |
Jeff Sharkey | 350083e | 2011-06-29 10:45:16 -0700 | [diff] [blame] | 651 | |
| 652 | final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); |
| 653 | if (start > 0) { |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 654 | pw.print("(omitting "); pw.print(start); pw.println(" buckets)"); |
Jeff Sharkey | 350083e | 2011-06-29 10:45:16 -0700 | [diff] [blame] | 655 | } |
| 656 | |
| 657 | for (int i = start; i < bucketCount; i++) { |
Jeff Sharkey | 55a442e | 2014-11-18 18:22:21 -0800 | [diff] [blame] | 658 | pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS); |
| 659 | if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); } |
| 660 | if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); } |
| 661 | if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); } |
| 662 | if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); } |
| 663 | if (operations != null) { pw.print(" op="); pw.print(operations[i]); } |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 664 | pw.println(); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 665 | } |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 666 | |
| 667 | pw.decreaseIndent(); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 668 | } |
| 669 | |
Jeff Sharkey | 55a442e | 2014-11-18 18:22:21 -0800 | [diff] [blame] | 670 | public void dumpCheckin(PrintWriter pw) { |
| 671 | pw.print("d,"); |
| 672 | pw.print(bucketDuration / SECOND_IN_MILLIS); |
| 673 | pw.println(); |
| 674 | |
| 675 | for (int i = 0; i < bucketCount; i++) { |
| 676 | pw.print("b,"); |
| 677 | pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(','); |
| 678 | if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(','); |
| 679 | if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(','); |
| 680 | if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(','); |
| 681 | if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(','); |
| 682 | if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); } |
| 683 | pw.println(); |
| 684 | } |
| 685 | } |
| 686 | |
Makoto Onuki | da65a52 | 2017-01-13 10:23:30 -0800 | [diff] [blame] | 687 | public void writeToProto(ProtoOutputStream proto, long tag) { |
| 688 | final long start = proto.start(tag); |
| 689 | |
| 690 | proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); |
| 691 | |
| 692 | for (int i = 0; i < bucketCount; i++) { |
| 693 | final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); |
| 694 | |
| 695 | proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); |
| 696 | writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); |
| 697 | writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); |
| 698 | writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); |
| 699 | writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); |
| 700 | writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); |
| 701 | |
| 702 | proto.end(startBucket); |
| 703 | } |
| 704 | |
| 705 | proto.end(start); |
| 706 | } |
| 707 | |
| 708 | private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) { |
| 709 | if (array != null) { |
| 710 | proto.write(tag, array[index]); |
| 711 | } |
| 712 | } |
| 713 | |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 714 | @Override |
| 715 | public String toString() { |
| 716 | final CharArrayWriter writer = new CharArrayWriter(); |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 717 | dump(new IndentingPrintWriter(writer, " "), false); |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 718 | return writer.toString(); |
| 719 | } |
| 720 | |
Mathew Inwood | 53f089f | 2018-08-08 14:44:44 +0100 | [diff] [blame] | 721 | @UnsupportedAppUsage |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 722 | public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() { |
Jeff Sharkey | bfdd680 | 2012-04-09 10:49:19 -0700 | [diff] [blame] | 723 | @Override |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 724 | public NetworkStatsHistory createFromParcel(Parcel in) { |
| 725 | return new NetworkStatsHistory(in); |
| 726 | } |
| 727 | |
Jeff Sharkey | bfdd680 | 2012-04-09 10:49:19 -0700 | [diff] [blame] | 728 | @Override |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 729 | public NetworkStatsHistory[] newArray(int size) { |
| 730 | return new NetworkStatsHistory[size]; |
| 731 | } |
| 732 | }; |
| 733 | |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 734 | private static long getLong(long[] array, int i, long value) { |
| 735 | return array != null ? array[i] : value; |
| 736 | } |
| 737 | |
| 738 | private static void setLong(long[] array, int i, long value) { |
| 739 | if (array != null) array[i] = value; |
| 740 | } |
| 741 | |
| 742 | private static void addLong(long[] array, int i, long value) { |
| 743 | if (array != null) array[i] += value; |
| 744 | } |
| 745 | |
Jeff Sharkey | 63abc37 | 2012-01-11 18:38:16 -0800 | [diff] [blame] | 746 | public int estimateResizeBuckets(long newBucketDuration) { |
| 747 | return (int) (size() * getBucketDuration() / newBucketDuration); |
| 748 | } |
| 749 | |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 750 | /** |
| 751 | * Utility methods for interacting with {@link DataInputStream} and |
| 752 | * {@link DataOutputStream}, mostly dealing with writing partial arrays. |
| 753 | */ |
| 754 | public static class DataStreamUtils { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 755 | @Deprecated |
| 756 | public static long[] readFullLongArray(DataInputStream in) throws IOException { |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 757 | final int size = in.readInt(); |
Jeff Sharkey | 1f99a48 | 2013-07-11 11:18:53 -0700 | [diff] [blame] | 758 | if (size < 0) throw new ProtocolException("negative array size"); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 759 | final long[] values = new long[size]; |
| 760 | for (int i = 0; i < values.length; i++) { |
| 761 | values[i] = in.readLong(); |
| 762 | } |
| 763 | return values; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 764 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 765 | |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 766 | /** |
| 767 | * Read variable-length {@link Long} using protobuf-style approach. |
| 768 | */ |
| 769 | public static long readVarLong(DataInputStream in) throws IOException { |
| 770 | int shift = 0; |
| 771 | long result = 0; |
| 772 | while (shift < 64) { |
| 773 | byte b = in.readByte(); |
| 774 | result |= (long) (b & 0x7F) << shift; |
| 775 | if ((b & 0x80) == 0) |
| 776 | return result; |
| 777 | shift += 7; |
| 778 | } |
| 779 | throw new ProtocolException("malformed long"); |
| 780 | } |
| 781 | |
| 782 | /** |
| 783 | * Write variable-length {@link Long} using protobuf-style approach. |
| 784 | */ |
| 785 | public static void writeVarLong(DataOutputStream out, long value) throws IOException { |
| 786 | while (true) { |
| 787 | if ((value & ~0x7FL) == 0) { |
| 788 | out.writeByte((int) value); |
| 789 | return; |
| 790 | } else { |
| 791 | out.writeByte(((int) value & 0x7F) | 0x80); |
| 792 | value >>>= 7; |
| 793 | } |
| 794 | } |
| 795 | } |
| 796 | |
| 797 | public static long[] readVarLongArray(DataInputStream in) throws IOException { |
| 798 | final int size = in.readInt(); |
| 799 | if (size == -1) return null; |
Jeff Sharkey | 1f99a48 | 2013-07-11 11:18:53 -0700 | [diff] [blame] | 800 | if (size < 0) throw new ProtocolException("negative array size"); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 801 | final long[] values = new long[size]; |
| 802 | for (int i = 0; i < values.length; i++) { |
| 803 | values[i] = readVarLong(in); |
| 804 | } |
| 805 | return values; |
| 806 | } |
| 807 | |
| 808 | public static void writeVarLongArray(DataOutputStream out, long[] values, int size) |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 809 | throws IOException { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 810 | if (values == null) { |
| 811 | out.writeInt(-1); |
| 812 | return; |
| 813 | } |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 814 | if (size > values.length) { |
| 815 | throw new IllegalArgumentException("size larger than length"); |
| 816 | } |
| 817 | out.writeInt(size); |
| 818 | for (int i = 0; i < size; i++) { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 819 | writeVarLong(out, values[i]); |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 820 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 821 | } |
| 822 | } |
| 823 | |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 824 | /** |
| 825 | * Utility methods for interacting with {@link Parcel} structures, mostly |
| 826 | * dealing with writing partial arrays. |
| 827 | */ |
| 828 | public static class ParcelUtils { |
| 829 | public static long[] readLongArray(Parcel in) { |
| 830 | final int size = in.readInt(); |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 831 | if (size == -1) return null; |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 832 | final long[] values = new long[size]; |
| 833 | for (int i = 0; i < values.length; i++) { |
| 834 | values[i] = in.readLong(); |
| 835 | } |
| 836 | return values; |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 837 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 838 | |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 839 | public static void writeLongArray(Parcel out, long[] values, int size) { |
Jeff Sharkey | 63d27a9 | 2011-08-03 17:04:22 -0700 | [diff] [blame] | 840 | if (values == null) { |
| 841 | out.writeInt(-1); |
| 842 | return; |
| 843 | } |
Jeff Sharkey | a63ba59 | 2011-07-19 23:47:12 -0700 | [diff] [blame] | 844 | if (size > values.length) { |
| 845 | throw new IllegalArgumentException("size larger than length"); |
| 846 | } |
| 847 | out.writeInt(size); |
| 848 | for (int i = 0; i < size; i++) { |
| 849 | out.writeLong(values[i]); |
| 850 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 851 | } |
Jeff Sharkey | 7527990 | 2011-05-24 18:39:45 -0700 | [diff] [blame] | 852 | } |
| 853 | |
| 854 | } |