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