NetworkStatsHistory.java revision d37948f6ed1667d077e0e3a38808f42f981ddcc2
175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/* 275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Copyright (C) 2011 The Android Open Source Project 375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * you may not use this file except in compliance with the License. 675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * You may obtain a copy of the License at 775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 1075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 1175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 1275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * See the License for the specific language governing permissions and 1475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * limitations under the License. 1575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 1675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 1775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypackage android.net; 1875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 1975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcel; 2075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcelable; 2175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 2275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.CharArrayWriter; 2375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataInputStream; 2475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataOutputStream; 2575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.IOException; 2675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.PrintWriter; 2761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.net.ProtocolException; 2875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Arrays; 2961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.util.Random; 3075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 3175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/** 3275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of historical network statistics, recorded into equally-sized 3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * "buckets" in time. Internally it stores data in {@code long} series for more 3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * efficient persistence. 3575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * <p> 3675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for 3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is 3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * sorted at all times. 3975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * 4075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * @hide 4175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistory implements Parcelable { 431b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey private static final int VERSION_INIT = 1; 4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 451b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey // TODO: teach about varint encoding to use less disk space 46d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey // TODO: extend to record rxPackets/txPackets 47d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey 48d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey private final long bucketDuration; 49d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey private int bucketCount; 50d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey private long[] bucketStart; 51d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey private long[] rxBytes; 52d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey private long[] txBytes; 53d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey 54d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public static class Entry { 55d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public long bucketStart; 56d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public long bucketDuration; 57d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public long rxBytes; 58d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public long txBytes; 59d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey } 6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 61d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public NetworkStatsHistory(long bucketDuration) { 624a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey this(bucketDuration, 10); 634a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey } 644a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey 654a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey public NetworkStatsHistory(long bucketDuration, int initialSize) { 6675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.bucketDuration = bucketDuration; 674a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey bucketStart = new long[initialSize]; 68d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rxBytes = new long[initialSize]; 69d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey txBytes = new long[initialSize]; 704a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey bucketCount = 0; 7175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 7275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 7375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory(Parcel in) { 7475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketDuration = in.readLong(); 7575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = readLongArray(in); 76d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rxBytes = in.createLongArray(); 77d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey txBytes = in.createLongArray(); 7875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount = bucketStart.length; 7975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 8075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 8175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** {@inheritDoc} */ 8275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void writeToParcel(Parcel out, int flags) { 8375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(bucketDuration); 8475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, bucketStart, bucketCount); 85d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey writeLongArray(out, rxBytes, bucketCount); 86d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey writeLongArray(out, txBytes, bucketCount); 8775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 8875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 8975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory(DataInputStream in) throws IOException { 9075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int version = in.readInt(); 9161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey switch (version) { 921b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey case VERSION_INIT: { 9361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketDuration = in.readLong(); 9461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketStart = readLongArray(in); 95d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rxBytes = readLongArray(in); 96d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey txBytes = readLongArray(in); 9761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketCount = bucketStart.length; 9861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey break; 9961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 10061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey default: { 10161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 10261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 10361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 10475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 10575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 10675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void writeToStream(DataOutputStream out) throws IOException { 1071b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey out.writeInt(VERSION_INIT); 10875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(bucketDuration); 10975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, bucketStart, bucketCount); 110d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey writeLongArray(out, rxBytes, bucketCount); 111d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey writeLongArray(out, txBytes, bucketCount); 11275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 11375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 11475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** {@inheritDoc} */ 11575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public int describeContents() { 11675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return 0; 11775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 11875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 119d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public int size() { 120d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey return bucketCount; 121d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey } 122d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey 123d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public long getBucketDuration() { 124d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey return bucketDuration; 125d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey } 126d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey 127d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey /** 128d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey * Return specific stats entry. 129d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey */ 130d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey public Entry getValues(int i, Entry recycle) { 131d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey final Entry entry = recycle != null ? recycle : new Entry(); 132d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey entry.bucketStart = bucketStart[i]; 133d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey entry.bucketDuration = bucketDuration; 134d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey entry.rxBytes = rxBytes[i]; 135d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey entry.txBytes = txBytes[i]; 136d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey return entry; 137d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey } 138d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey 13975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 14075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Record that data traffic occurred in the given time range. Will 14175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * distribute across internal buckets, creating new buckets as needed. 14275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 14375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void recordData(long start, long end, long rx, long tx) { 1441b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey if (rx < 0 || tx < 0) { 1451b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey throw new IllegalArgumentException( 1461b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey "tried recording negative data: rx=" + rx + ", tx=" + tx); 1471b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey } 1481b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey 14975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create any buckets needed by this range 15075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey ensureBuckets(start, end); 15175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 15275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // distribute data usage into buckets 15375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long duration = end - start; 15475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = bucketCount - 1; i >= 0; i--) { 15575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curStart = bucketStart[i]; 15675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curEnd = curStart + bucketDuration; 15775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 15875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket is older than record; we're finished 15975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curEnd < start) break; 16075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket is newer than record; keep looking 16175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curStart > end) continue; 16275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 16375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); 16475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (overlap > 0) { 165d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey this.rxBytes[i] += rx * overlap / duration; 166d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey this.txBytes[i] += tx * overlap / duration; 16775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 16875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 16975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 17075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 17175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 17219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * Record an entire {@link NetworkStatsHistory} into this history. Usually 17319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * for combining together stats for external reporting. 17419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey */ 17519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey public void recordEntireHistory(NetworkStatsHistory input) { 17619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey for (int i = 0; i < input.bucketCount; i++) { 17719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long start = input.bucketStart[i]; 17819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long end = start + input.bucketDuration; 179d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey recordData(start, end, input.rxBytes[i], input.txBytes[i]); 18019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 18119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 18219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 18319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey /** 18475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Ensure that buckets exist for given time range, creating as needed. 18575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 18675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private void ensureBuckets(long start, long end) { 18775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // normalize incoming range to bucket boundaries 18875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey start -= start % bucketDuration; 18975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey end += (bucketDuration - (end % bucketDuration)) % bucketDuration; 19075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 19175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (long now = start; now < end; now += bucketDuration) { 19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // try finding existing bucket 19375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); 19475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (index < 0) { 19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket missing, create and insert 19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey insertBucket(~index, now); 19775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 19875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 19975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 20075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 20175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 20275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Insert new bucket at requested index and starting time. 20375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 20475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private void insertBucket(int index, long start) { 20575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create more buckets when needed 2064a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey if (bucketCount >= bucketStart.length) { 2074a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; 20875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = Arrays.copyOf(bucketStart, newLength); 209d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rxBytes = Arrays.copyOf(rxBytes, newLength); 210d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey txBytes = Arrays.copyOf(txBytes, newLength); 21175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 21275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 21375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create gap when inserting bucket in middle 21475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (index < bucketCount) { 21575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int dstPos = index + 1; 21675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int length = bucketCount - index; 21775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 21875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(bucketStart, index, bucketStart, dstPos, length); 219d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey System.arraycopy(rxBytes, index, rxBytes, dstPos, length); 220d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey System.arraycopy(txBytes, index, txBytes, dstPos, length); 22175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 22275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 22375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart[index] = start; 224d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rxBytes[index] = 0; 225d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey txBytes[index] = 0; 22675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount++; 22775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 22875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 22975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 23075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Remove buckets older than requested cutoff. 23175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 23275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void removeBucketsBefore(long cutoff) { 23375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey int i; 23475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (i = 0; i < bucketCount; i++) { 23575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curStart = bucketStart[i]; 23675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curEnd = curStart + bucketDuration; 23775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 23875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // cutoff happens before or during this bucket; everything before 23975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // this bucket should be removed. 24075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curEnd > cutoff) break; 24175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 24275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 24375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (i > 0) { 24475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int length = bucketStart.length; 24575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = Arrays.copyOfRange(bucketStart, i, length); 246d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rxBytes = Arrays.copyOfRange(rxBytes, i, length); 247d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey txBytes = Arrays.copyOfRange(txBytes, i, length); 24875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount -= i; 24975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 25075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 25175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 25261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey /** 25319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * Return interpolated data usage across the requested range. Interpolates 25419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * across buckets, so values may be rounded slightly. 25519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey */ 2563f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey public long[] getTotalData(long start, long end, long[] outTotal) { 25719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey long rx = 0; 25819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey long tx = 0; 25919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 26019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey for (int i = bucketCount - 1; i >= 0; i--) { 26119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long curStart = bucketStart[i]; 26219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long curEnd = curStart + bucketDuration; 26319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 26419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey // bucket is older than record; we're finished 26519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (curEnd < start) break; 26619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey // bucket is newer than record; keep looking 26719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (curStart > end) continue; 26819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 26919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); 27019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (overlap > 0) { 271d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey rx += this.rxBytes[i] * overlap / bucketDuration; 272d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey tx += this.txBytes[i] * overlap / bucketDuration; 27319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 27419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 27519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 2763f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey if (outTotal == null || outTotal.length != 2) { 2773f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey outTotal = new long[2]; 2783f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey } 27919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey outTotal[0] = rx; 28019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey outTotal[1] = tx; 2813f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey return outTotal; 28219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 28319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 28419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey /** 28561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey * @deprecated only for temporary testing 28661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey */ 28761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey @Deprecated 28861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey public void generateRandom(long start, long end, long rx, long tx) { 28961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey ensureBuckets(start, end); 29061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 29161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final Random r = new Random(); 29261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey while (rx > 1024 && tx > 1024) { 29361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curStart = randomLong(r, start, end); 29461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curEnd = randomLong(r, curStart, end); 29561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curRx = randomLong(r, 0, rx); 29661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curTx = randomLong(r, 0, tx); 29761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 29861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey recordData(curStart, curEnd, curRx, curTx); 29961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 30061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey rx -= curRx; 30161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey tx -= curTx; 30261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 30361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 30461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 30561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey private static long randomLong(Random r, long start, long end) { 30661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey return (long) (start + (r.nextFloat() * (end - start))); 30761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 30861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 309350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey public void dump(String prefix, PrintWriter pw, boolean fullHistory) { 31075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(prefix); 31161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); 312350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey 313350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); 314350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey if (start > 0) { 315350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey pw.print(prefix); 316350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey pw.print(" (omitting "); pw.print(start); pw.println(" buckets)"); 317350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey } 318350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey 319350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey for (int i = start; i < bucketCount; i++) { 32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(prefix); 32161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey pw.print(" bucketStart="); pw.print(bucketStart[i]); 322d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey pw.print(" rxBytes="); pw.print(rxBytes[i]); 323d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey pw.print(" txBytes="); pw.println(txBytes[i]); 32475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 32575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 32675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 32775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey @Override 32875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public String toString() { 32975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final CharArrayWriter writer = new CharArrayWriter(); 330350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey dump("", new PrintWriter(writer), false); 33175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return writer.toString(); 33275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 33475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() { 33575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory createFromParcel(Parcel in) { 33675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return new NetworkStatsHistory(in); 33775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 33975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory[] newArray(int size) { 34075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return new NetworkStatsHistory[size]; 34175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 34275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey }; 34375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 34475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static long[] readLongArray(DataInputStream in) throws IOException { 34575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int size = in.readInt(); 34675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long[] values = new long[size]; 34775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < values.length; i++) { 34875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey values[i] = in.readLong(); 34975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 35075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return values; 35175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 35275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 35375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static void writeLongArray(DataOutputStream out, long[] values, int size) throws IOException { 35475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (size > values.length) { 35575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey throw new IllegalArgumentException("size larger than length"); 35675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 35775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeInt(size); 35875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < size; i++) { 35975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(values[i]); 36075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 36175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 36275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 36375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static long[] readLongArray(Parcel in) { 36475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int size = in.readInt(); 36575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long[] values = new long[size]; 36675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < values.length; i++) { 36775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey values[i] = in.readLong(); 36875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 36975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return values; 37075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 37175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 37275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static void writeLongArray(Parcel out, long[] values, int size) { 37375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (size > values.length) { 37475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey throw new IllegalArgumentException("size larger than length"); 37575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 37675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeInt(size); 37775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < size; i++) { 37875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(values[i]); 37975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 38075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 38175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 38275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey} 383