NetworkStatsHistory.java revision 350083e36b9db6062e165954403ef921ff3dfdad
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 4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public final long bucketDuration; 4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 49d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public int bucketCount; 50d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public long[] bucketStart; 51d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public long[] rx; 52d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public long[] tx; 5375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 54d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey public NetworkStatsHistory(long bucketDuration) { 554a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey this(bucketDuration, 10); 564a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey } 574a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey 584a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey public NetworkStatsHistory(long bucketDuration, int initialSize) { 5975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.bucketDuration = bucketDuration; 604a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey bucketStart = new long[initialSize]; 614a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey rx = new long[initialSize]; 624a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey tx = new long[initialSize]; 634a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey bucketCount = 0; 6475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 6575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 6675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory(Parcel in) { 6775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketDuration = in.readLong(); 6875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = readLongArray(in); 6975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx = in.createLongArray(); 7075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx = in.createLongArray(); 7175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount = bucketStart.length; 7275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 7375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 7475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** {@inheritDoc} */ 7575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void writeToParcel(Parcel out, int flags) { 7675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(bucketDuration); 7775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, bucketStart, bucketCount); 7875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, rx, bucketCount); 7975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, tx, bucketCount); 8075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 8175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 8275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory(DataInputStream in) throws IOException { 8375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int version = in.readInt(); 8461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey switch (version) { 851b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey case VERSION_INIT: { 8661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketDuration = in.readLong(); 8761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketStart = readLongArray(in); 8861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey rx = readLongArray(in); 8961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey tx = readLongArray(in); 9061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey bucketCount = bucketStart.length; 9161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey break; 9261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 9361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey default: { 9461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey throw new ProtocolException("unexpected version: " + version); 9561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 9661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 9775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 9875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 9975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void writeToStream(DataOutputStream out) throws IOException { 1001b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey out.writeInt(VERSION_INIT); 10175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(bucketDuration); 10275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, bucketStart, bucketCount); 10375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, rx, bucketCount); 10475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey writeLongArray(out, tx, bucketCount); 10575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 10675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 10775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** {@inheritDoc} */ 10875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public int describeContents() { 10975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return 0; 11075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 11175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 11275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 11375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Record that data traffic occurred in the given time range. Will 11475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * distribute across internal buckets, creating new buckets as needed. 11575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 11675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void recordData(long start, long end, long rx, long tx) { 1171b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey if (rx < 0 || tx < 0) { 1181b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey throw new IllegalArgumentException( 1191b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey "tried recording negative data: rx=" + rx + ", tx=" + tx); 1201b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey } 1211b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey 12275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create any buckets needed by this range 12375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey ensureBuckets(start, end); 12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 12575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // distribute data usage into buckets 12675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long duration = end - start; 12775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = bucketCount - 1; i >= 0; i--) { 12875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curStart = bucketStart[i]; 12975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curEnd = curStart + bucketDuration; 13075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 13175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket is older than record; we're finished 13275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curEnd < start) break; 13375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket is newer than record; keep looking 13475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curStart > end) continue; 13575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 13675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); 13775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (overlap > 0) { 13875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.rx[i] += rx * overlap / duration; 13975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey this.tx[i] += tx * overlap / duration; 14075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 14175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 14275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 14375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 14475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 14519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * Record an entire {@link NetworkStatsHistory} into this history. Usually 14619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * for combining together stats for external reporting. 14719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey */ 14819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey public void recordEntireHistory(NetworkStatsHistory input) { 14919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey for (int i = 0; i < input.bucketCount; i++) { 15019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long start = input.bucketStart[i]; 15119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long end = start + input.bucketDuration; 15219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey recordData(start, end, input.rx[i], input.tx[i]); 15319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 15419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 15519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 15619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey /** 15775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Ensure that buckets exist for given time range, creating as needed. 15875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 15975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private void ensureBuckets(long start, long end) { 16075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // normalize incoming range to bucket boundaries 16175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey start -= start % bucketDuration; 16275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey end += (bucketDuration - (end % bucketDuration)) % bucketDuration; 16375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 16475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (long now = start; now < end; now += bucketDuration) { 16575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // try finding existing bucket 16675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); 16775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (index < 0) { 16875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // bucket missing, create and insert 16975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey insertBucket(~index, now); 17075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 17175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 17275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 17375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 17475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 17575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Insert new bucket at requested index and starting time. 17675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 17775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private void insertBucket(int index, long start) { 17875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create more buckets when needed 1794a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey if (bucketCount >= bucketStart.length) { 1804a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; 18175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = Arrays.copyOf(bucketStart, newLength); 18275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx = Arrays.copyOf(rx, newLength); 18375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx = Arrays.copyOf(tx, newLength); 18475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 18575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 18675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // create gap when inserting bucket in middle 18775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (index < bucketCount) { 18875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int dstPos = index + 1; 18975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int length = bucketCount - index; 19075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 19175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(bucketStart, index, bucketStart, dstPos, length); 19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(rx, index, rx, dstPos, length); 19375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey System.arraycopy(tx, index, tx, dstPos, length); 19475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart[index] = start; 19775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx[index] = 0; 19875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx[index] = 0; 19975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount++; 20075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 20175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 20275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey /** 20375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Remove buckets older than requested cutoff. 20475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */ 20575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public void removeBucketsBefore(long cutoff) { 20675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey int i; 20775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (i = 0; i < bucketCount; i++) { 20875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curStart = bucketStart[i]; 20975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long curEnd = curStart + bucketDuration; 21075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 21175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // cutoff happens before or during this bucket; everything before 21275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey // this bucket should be removed. 21375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (curEnd > cutoff) break; 21475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 21575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 21675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (i > 0) { 21775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int length = bucketStart.length; 21875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketStart = Arrays.copyOfRange(bucketStart, i, length); 21975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey rx = Arrays.copyOfRange(rx, i, length); 22075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey tx = Arrays.copyOfRange(tx, i, length); 22175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey bucketCount -= i; 22275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 22375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 22475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 22561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey /** 22619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * Return interpolated data usage across the requested range. Interpolates 22719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey * across buckets, so values may be rounded slightly. 22819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey */ 2293f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey public long[] getTotalData(long start, long end, long[] outTotal) { 23019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey long rx = 0; 23119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey long tx = 0; 23219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 23319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey for (int i = bucketCount - 1; i >= 0; i--) { 23419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long curStart = bucketStart[i]; 23519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long curEnd = curStart + bucketDuration; 23619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 23719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey // bucket is older than record; we're finished 23819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (curEnd < start) break; 23919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey // bucket is newer than record; keep looking 24019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (curStart > end) continue; 24119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 24219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); 24319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey if (overlap > 0) { 24419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey rx += this.rx[i] * overlap / bucketDuration; 24519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey tx += this.tx[i] * overlap / bucketDuration; 24619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 24719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 24819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 2493f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey if (outTotal == null || outTotal.length != 2) { 2503f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey outTotal = new long[2]; 2513f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey } 25219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey outTotal[0] = rx; 25319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey outTotal[1] = tx; 2543f3913550c10792edb8aecf66cc83c3db5c8b311Jeff Sharkey return outTotal; 25519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey } 25619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey 25719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey /** 25861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey * @deprecated only for temporary testing 25961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey */ 26061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey @Deprecated 26161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey public void generateRandom(long start, long end, long rx, long tx) { 26261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey ensureBuckets(start, end); 26361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 26461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final Random r = new Random(); 26561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey while (rx > 1024 && tx > 1024) { 26661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curStart = randomLong(r, start, end); 26761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curEnd = randomLong(r, curStart, end); 26861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curRx = randomLong(r, 0, rx); 26961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey final long curTx = randomLong(r, 0, tx); 27061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 27161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey recordData(curStart, curEnd, curRx, curTx); 27261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 27361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey rx -= curRx; 27461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey tx -= curTx; 27561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 27661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 27761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 27861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey private static long randomLong(Random r, long start, long end) { 27961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey return (long) (start + (r.nextFloat() * (end - start))); 28061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey } 28161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey 282350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey public void dump(String prefix, PrintWriter pw, boolean fullHistory) { 28375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(prefix); 28461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); 285350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey 286350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); 287350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey if (start > 0) { 288350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey pw.print(prefix); 289350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey pw.print(" (omitting "); pw.print(start); pw.println(" buckets)"); 290350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey } 291350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey 292350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey for (int i = start; i < bucketCount; i++) { 29375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(prefix); 29461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey pw.print(" bucketStart="); pw.print(bucketStart[i]); 29575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(" rx="); pw.print(rx[i]); 29675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey pw.print(" tx="); pw.println(tx[i]); 29775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 29875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 29975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 30075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey @Override 30175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public String toString() { 30275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final CharArrayWriter writer = new CharArrayWriter(); 303350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey dump("", new PrintWriter(writer), false); 30475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return writer.toString(); 30575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 30675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 30775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() { 30875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory createFromParcel(Parcel in) { 30975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return new NetworkStatsHistory(in); 31075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 31175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 31275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey public NetworkStatsHistory[] newArray(int size) { 31375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return new NetworkStatsHistory[size]; 31475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey }; 31675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 31775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static long[] readLongArray(DataInputStream in) throws IOException { 31875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int size = in.readInt(); 31975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long[] values = new long[size]; 32075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < values.length; i++) { 32175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey values[i] = in.readLong(); 32275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 32375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return values; 32475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 32575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 32675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static void writeLongArray(DataOutputStream out, long[] values, int size) throws IOException { 32775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (size > values.length) { 32875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey throw new IllegalArgumentException("size larger than length"); 32975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeInt(size); 33175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < size; i++) { 33275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(values[i]); 33375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 33575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 33675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static long[] readLongArray(Parcel in) { 33775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final int size = in.readInt(); 33875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey final long[] values = new long[size]; 33975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < values.length; i++) { 34075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey values[i] = in.readLong(); 34175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 34275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey return values; 34375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 34475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 34575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey private static void writeLongArray(Parcel out, long[] values, int size) { 34675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey if (size > values.length) { 34775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey throw new IllegalArgumentException("size larger than length"); 34875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 34975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeInt(size); 35075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey for (int i = 0; i < size; i++) { 35175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey out.writeLong(values[i]); 35275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 35375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey } 35475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey 35575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey} 356