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
19a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStats.IFACE_ALL;
20b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkeyimport static android.net.NetworkStats.SET_DEFAULT;
21a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStats.TAG_NONE;
22a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStats.UID_ALL;
2363d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray;
2463d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray;
2563d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
2663d27a9233fed934340231f438493746084a681dJeff Sharkeyimport static android.net.NetworkStatsHistory.Entry.UNKNOWN;
27a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
28a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkeyimport static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
2955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport static android.text.format.DateUtils.SECOND_IN_MILLIS;
30f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
3163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static com.android.internal.util.ArrayUtils.total;
32a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
3375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcel;
3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcelable;
35da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsHistoryBucketProto;
36da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.service.NetworkStatsHistoryProto;
3769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkeyimport android.util.MathUtils;
38da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onukiimport android.util.proto.ProtoOutputStream;
3975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
4163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.CharArrayWriter;
4375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataInputStream;
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataOutputStream;
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.IOException;
4655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkeyimport java.io.PrintWriter;
4761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.net.ProtocolException;
4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Arrays;
4961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.util.Random;
5075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
5175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/**
5275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of historical network statistics, recorded into equally-sized
5375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * "buckets" in time. Internally it stores data in {@code long} series for more
5475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * efficient persistence.
5575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * <p>
5675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for
5775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is
5875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * sorted at all times.
5975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * @hide
6175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */
6275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistory implements Parcelable {
631b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    private static final int VERSION_INIT = 1;
6463d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final int VERSION_ADD_PACKETS = 2;
65558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static final int VERSION_ADD_ACTIVE = 3;
6675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
67558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_ACTIVE_TIME = 0x01;
68558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_BYTES = 0x02;
69558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_PACKETS = 0x04;
70558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_BYTES = 0x08;
71558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_PACKETS = 0x10;
72558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_OPERATIONS = 0x20;
73d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
7463d27a9233fed934340231f438493746084a681dJeff Sharkey    public static final int FIELD_ALL = 0xFFFFFFFF;
7563d27a9233fed934340231f438493746084a681dJeff Sharkey
7663d27a9233fed934340231f438493746084a681dJeff Sharkey    private long bucketDuration;
77d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int bucketCount;
78d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] bucketStart;
79558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private long[] activeTime;
80d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
81a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] rxPackets;
82d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
83a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] txPackets;
8463d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
8563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long totalBytes;
86d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
87d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public static class Entry {
8863d27a9233fed934340231f438493746084a681dJeff Sharkey        public static final long UNKNOWN = -1;
8963d27a9233fed934340231f438493746084a681dJeff Sharkey
90d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long bucketDuration;
91558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long bucketStart;
92558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long activeTime;
93d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long rxBytes;
94a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long rxPackets;
95d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long txBytes;
96a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long txPackets;
9763d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
98d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
9975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
100d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey    public NetworkStatsHistory(long bucketDuration) {
10163d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, 10, FIELD_ALL);
1024a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    }
1034a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey
1044a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize) {
10563d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, initialSize, FIELD_ALL);
10663d27a9233fed934340231f438493746084a681dJeff Sharkey    }
10763d27a9233fed934340231f438493746084a681dJeff Sharkey
10863d27a9233fed934340231f438493746084a681dJeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
10975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        this.bucketDuration = bucketDuration;
1104a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketStart = new long[initialSize];
111558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize];
11263d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
11363d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
11463d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
11563d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
11663d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
1174a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketCount = 0;
11863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = 0;
11963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
12063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
12163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
12263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
12363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        recordEntireHistory(existing);
12475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
12575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(Parcel in) {
12775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketDuration = in.readLong();
12875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart = readLongArray(in);
129558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        activeTime = readLongArray(in);
130a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxBytes = readLongArray(in);
131a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxPackets = readLongArray(in);
132a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txBytes = readLongArray(in);
133a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txPackets = readLongArray(in);
13463d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = readLongArray(in);
13575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount = bucketStart.length;
13663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = in.readLong();
13775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
13875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
139bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
14075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToParcel(Parcel out, int flags) {
14175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
14275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        writeLongArray(out, bucketStart, bucketCount);
143558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeLongArray(out, activeTime, bucketCount);
144d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, rxBytes, bucketCount);
145a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, rxPackets, bucketCount);
146d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, txBytes, bucketCount);
147a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, txPackets, bucketCount);
14863d27a9233fed934340231f438493746084a681dJeff Sharkey        writeLongArray(out, operations, bucketCount);
14963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeLong(totalBytes);
15075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
15175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
15275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(DataInputStream in) throws IOException {
15375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final int version = in.readInt();
15461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        switch (version) {
1551b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            case VERSION_INIT: {
15661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketDuration = in.readLong();
15763d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readFullLongArray(in);
15863d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readFullLongArray(in);
159a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                rxPackets = new long[bucketStart.length];
16063d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readFullLongArray(in);
161a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                txPackets = new long[bucketStart.length];
16263d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = new long[bucketStart.length];
16363d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketCount = bucketStart.length;
16463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
16563d27a9233fed934340231f438493746084a681dJeff Sharkey                break;
16663d27a9233fed934340231f438493746084a681dJeff Sharkey            }
167558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_PACKETS:
168558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_ACTIVE: {
16963d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketDuration = in.readLong();
17063d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readVarLongArray(in);
171558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in)
172558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                        : new long[bucketStart.length];
17363d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readVarLongArray(in);
17463d27a9233fed934340231f438493746084a681dJeff Sharkey                rxPackets = readVarLongArray(in);
17563d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readVarLongArray(in);
17663d27a9233fed934340231f438493746084a681dJeff Sharkey                txPackets = readVarLongArray(in);
17763d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = readVarLongArray(in);
17861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketCount = bucketStart.length;
17963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
18061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                break;
18161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
18261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            default: {
18361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                throw new ProtocolException("unexpected version: " + version);
18461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
18561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
186b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey
187b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey        if (bucketStart.length != bucketCount || rxBytes.length != bucketCount
188b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey                || rxPackets.length != bucketCount || txBytes.length != bucketCount
189b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey                || txPackets.length != bucketCount || operations.length != bucketCount) {
190b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey            throw new ProtocolException("Mismatched history lengths");
191b0a579f83369ca2daa885222a35f1cd3c054ab11Jeff Sharkey        }
19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
19375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
19475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToStream(DataOutputStream out) throws IOException {
195558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        out.writeInt(VERSION_ADD_ACTIVE);
19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
19763d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, bucketStart, bucketCount);
198558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeVarLongArray(out, activeTime, bucketCount);
19963d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxBytes, bucketCount);
20063d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxPackets, bucketCount);
20163d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txBytes, bucketCount);
20263d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txPackets, bucketCount);
20363d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, operations, bucketCount);
20475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
20575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
206bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
20775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public int describeContents() {
20875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return 0;
20975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
21075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
211d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int size() {
212d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketCount;
213d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
214d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
215d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public long getBucketDuration() {
216d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketDuration;
217d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
218d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
219434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getStart() {
220434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
221434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[0];
222434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
223434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MAX_VALUE;
224434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
225434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
226434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
227434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getEnd() {
228434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
229434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[bucketCount - 1] + bucketDuration;
230434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
231434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MIN_VALUE;
232434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
233434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
234434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
235d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    /**
23663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Return total bytes represented by this history.
23763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
23863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getTotalBytes() {
23963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return totalBytes;
24063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
24163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
24263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
24369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately before the
24469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
24569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
24669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexBefore(long time) {
24769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
24869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
24969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = (~index) - 1;
25069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
25169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index -= 1;
25269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
25369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
25469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
25569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
25669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
25769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately after the
25869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
25969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
26069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexAfter(long time) {
26169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
26269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
26369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = ~index;
26469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
26569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index += 1;
26669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
26769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
26869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
26969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
27069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
271d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     * Return specific stats entry.
272d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     */
273d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public Entry getValues(int i, Entry recycle) {
274d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
275d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketStart = bucketStart[i];
276d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketDuration = bucketDuration;
277558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = getLong(activeTime, i, UNKNOWN);
27863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
27963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
28063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = getLong(txBytes, i, UNKNOWN);
28163d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = getLong(txPackets, i, UNKNOWN);
28263d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = getLong(operations, i, UNKNOWN);
283d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return entry;
284d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
285d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
286f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    public void setValues(int i, Entry entry) {
287f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Unwind old values
288f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        if (rxBytes != null) totalBytes -= rxBytes[i];
289f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        if (txBytes != null) totalBytes -= txBytes[i];
290f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
291f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        bucketStart[i] = entry.bucketStart;
292f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        setLong(activeTime, i, entry.activeTime);
293f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        setLong(rxBytes, i, entry.rxBytes);
294f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        setLong(rxPackets, i, entry.rxPackets);
295f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        setLong(txBytes, i, entry.txBytes);
296f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        setLong(txPackets, i, entry.txPackets);
297f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        setLong(operations, i, entry.operations);
298f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
299f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        // Apply new values
300f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        if (rxBytes != null) totalBytes += rxBytes[i];
301f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey        if (txBytes != null) totalBytes += txBytes[i];
302f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey    }
303f4de294297de47d8c594956b2d8607e314e71836Jeff Sharkey
30475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
30575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
30675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
30775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
308a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    @Deprecated
309a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, long rxBytes, long txBytes) {
310b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        recordData(start, end, new NetworkStats.Entry(
311b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
312a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
313a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
314a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
315a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
316a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
317a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
318a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, NetworkStats.Entry entry) {
31963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxBytes = entry.rxBytes;
32063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxPackets = entry.rxPackets;
32163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txBytes = entry.txBytes;
32263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txPackets = entry.txPackets;
32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long operations = entry.operations;
32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isNegative()) {
326a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            throw new IllegalArgumentException("tried recording negative data");
3271b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isEmpty()) {
329367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey            return;
330367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey        }
3311b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
33275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create any buckets needed by this range
33375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        ensureBuckets(start, end);
33475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
33575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // distribute data usage into buckets
336a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        long duration = end - start;
33769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
33869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
33975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
34075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
34175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
34275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is older than record; we're finished
34375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd < start) break;
34475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is newer than record; keep looking
34575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curStart > end) continue;
34675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
34775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
348a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
349a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
350a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
35163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxBytes = rxBytes * overlap / duration;
35263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxPackets = rxPackets * overlap / duration;
35363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxBytes = txBytes * overlap / duration;
35463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxPackets = txPackets * overlap / duration;
35563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracOperations = operations * overlap / duration;
356a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
357558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            addLong(activeTime, i, overlap);
35863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
35963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
36063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
36163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
36263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.operations, i, fracOperations); operations -= fracOperations;
363a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
364a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            duration -= overlap;
36575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
36663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
36763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes += entry.rxBytes + entry.txBytes;
36875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
36975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
37075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
37119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Record an entire {@link NetworkStatsHistory} into this history. Usually
37219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * for combining together stats for external reporting.
37319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
37419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void recordEntireHistory(NetworkStatsHistory input) {
37570c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey        recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE);
37670c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    }
37770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
37870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    /**
37970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * Record given {@link NetworkStatsHistory} into this history, copying only
38070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * buckets that atomically occur in the inclusive time range. Doesn't
38170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     * interpolate across partial buckets.
38270c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey     */
38370c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey    public void recordHistory(NetworkStatsHistory input, long start, long end) {
384a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
385b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
38619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        for (int i = 0; i < input.bucketCount; i++) {
38770c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            final long bucketStart = input.bucketStart[i];
38870c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            final long bucketEnd = bucketStart + input.bucketDuration;
38970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey
39070c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            // skip when bucket is outside requested range
39170c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            if (bucketStart < start || bucketEnd > end) continue;
392a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
39363d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = getLong(input.rxBytes, i, 0L);
39463d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = getLong(input.rxPackets, i, 0L);
39563d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = getLong(input.txBytes, i, 0L);
39663d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = getLong(input.txPackets, i, 0L);
39763d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = getLong(input.operations, i, 0L);
398a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
39970c70530bd6793869736ec894498e4ebf5dc9b20Jeff Sharkey            recordData(bucketStart, bucketEnd, entry);
40019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
40119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
40219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
40319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
40475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Ensure that buckets exist for given time range, creating as needed.
40575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
40675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void ensureBuckets(long start, long end) {
40775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // normalize incoming range to bucket boundaries
40875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        start -= start % bucketDuration;
40975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        end += (bucketDuration - (end % bucketDuration)) % bucketDuration;
41075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
41175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (long now = start; now < end; now += bucketDuration) {
41275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // try finding existing bucket
41375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now);
41475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (index < 0) {
41575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                // bucket missing, create and insert
41675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                insertBucket(~index, now);
41775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
41875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
41975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
42075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
42175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
42275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Insert new bucket at requested index and starting time.
42375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
42475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void insertBucket(int index, long start) {
42575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create more buckets when needed
4264a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (bucketCount >= bucketStart.length) {
4274a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey            final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
42875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOf(bucketStart, newLength);
429558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength);
43063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
43163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
43263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
43363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
43463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOf(operations, newLength);
43575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
43675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
43775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create gap when inserting bucket in middle
43875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (index < bucketCount) {
43975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int dstPos = index + 1;
44075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketCount - index;
44175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
44275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
443558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length);
44463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
44563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
44663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
44763d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
44863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
44975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
45075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
45175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart[index] = start;
452558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        setLong(activeTime, index, 0L);
45363d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxBytes, index, 0L);
45463d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxPackets, index, 0L);
45563d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txBytes, index, 0L);
45663d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txPackets, index, 0L);
45763d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(operations, index, 0L);
45875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount++;
45975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
46075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
46175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
46275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Remove buckets older than requested cutoff.
46375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
46463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    @Deprecated
46575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void removeBucketsBefore(long cutoff) {
46675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        int i;
46775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (i = 0; i < bucketCount; i++) {
46875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
46975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
47075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
47175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // cutoff happens before or during this bucket; everything before
47275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // this bucket should be removed.
47375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd > cutoff) break;
47475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
47575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
47675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (i > 0) {
47775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketStart.length;
47875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOfRange(bucketStart, i, length);
479558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length);
48063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
48163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
48263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
48363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
48463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
48575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketCount -= i;
48663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
48763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // TODO: subtract removed values from totalBytes
48875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
48975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
49075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
49161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
49219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
49319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * across buckets, so values may be rounded slightly.
49419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
495434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, Entry recycle) {
496434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return getValues(start, end, Long.MAX_VALUE, recycle);
497434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
498434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
499434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    /**
500434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
501434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * across buckets, so values may be rounded slightly.
502434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     */
503434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, long now, Entry recycle) {
504434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
505434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        entry.bucketDuration = end - start;
506558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.bucketStart = start;
507558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = activeTime != null ? 0 : UNKNOWN;
50863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
50963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
51063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = txBytes != null ? 0 : UNKNOWN;
51163d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = txPackets != null ? 0 : UNKNOWN;
51263d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = operations != null ? 0 : UNKNOWN;
51319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
51469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
51569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
51619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curStart = bucketStart[i];
51719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curEnd = curStart + bucketDuration;
51819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
51934c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is older than request; we're finished
52034c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curEnd <= start) break;
52134c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is newer than request; keep looking
52234c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curStart >= end) continue;
52319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
524434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            // include full value for active buckets, otherwise only fractional
525434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            final boolean activeBucket = curStart < now && curEnd > now;
52669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            final long overlap;
52769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            if (activeBucket) {
52869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = bucketDuration;
52969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            } else {
53069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapEnd = curEnd < end ? curEnd : end;
53169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapStart = curStart > start ? curStart : start;
53269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = overlapEnd - overlapStart;
53369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            }
534a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
535a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
536a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
537558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration;
53863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
53963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
54063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
54163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
54263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
54319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
544434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return entry;
54519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
54619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
54719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
54861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * @deprecated only for temporary testing
54961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
55061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    @Deprecated
551293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public void generateRandom(long start, long end, long bytes) {
552293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final Random r = new Random();
553293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
554293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final float fractionRx = r.nextFloat();
555293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxBytes = (long) (bytes * fractionRx);
556293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txBytes = (long) (bytes * (1 - fractionRx));
557293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
558293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxPackets = rxBytes / 1024;
559293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txPackets = txBytes / 1024;
560293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long operations = rxBytes / 2048;
561293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
562293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r);
563293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    }
564293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
565293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    /**
566293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     * @deprecated only for temporary testing
567293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     */
568293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    @Deprecated
56963d27a9233fed934340231f438493746084a681dJeff Sharkey    public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
570293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            long txPackets, long operations, Random r) {
57161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        ensureBuckets(start, end);
57261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
573a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
574b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
57504cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey        while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
57604cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey                || operations > 32) {
57761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            final long curStart = randomLong(r, start, end);
578293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2);
57963d27a9233fed934340231f438493746084a681dJeff Sharkey
58063d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = randomLong(r, 0, rxBytes);
58163d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = randomLong(r, 0, rxPackets);
58263d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = randomLong(r, 0, txBytes);
58363d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = randomLong(r, 0, txPackets);
58463d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = randomLong(r, 0, operations);
58563d27a9233fed934340231f438493746084a681dJeff Sharkey
58663d27a9233fed934340231f438493746084a681dJeff Sharkey            rxBytes -= entry.rxBytes;
58763d27a9233fed934340231f438493746084a681dJeff Sharkey            rxPackets -= entry.rxPackets;
58863d27a9233fed934340231f438493746084a681dJeff Sharkey            txBytes -= entry.txBytes;
58963d27a9233fed934340231f438493746084a681dJeff Sharkey            txPackets -= entry.txPackets;
59063d27a9233fed934340231f438493746084a681dJeff Sharkey            operations -= entry.operations;
591f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
592f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            recordData(curStart, curEnd, entry);
59361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
59461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
59561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
596293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public static long randomLong(Random r, long start, long end) {
59761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return (long) (start + (r.nextFloat() * (end - start)));
59861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
59961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
60055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    /**
60155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey     * Quickly determine if this history intersects with given window.
60255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey     */
60355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public boolean intersects(long start, long end) {
60455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final long dataStart = getStart();
60555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        final long dataEnd = getEnd();
60655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (start >= dataStart && start <= dataEnd) return true;
60755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (end >= dataStart && end <= dataEnd) return true;
60855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (dataStart >= start && dataStart <= end) return true;
60955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        if (dataEnd >= start && dataEnd <= end) return true;
61055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        return false;
61155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
61255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
61363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dump(IndentingPrintWriter pw, boolean fullHistory) {
61455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print("NetworkStatsHistory: bucketDuration=");
61555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.println(bucketDuration / SECOND_IN_MILLIS);
61663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.increaseIndent();
617350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
618350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
619350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (start > 0) {
62063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
621350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        }
622350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
623350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        for (int i = start; i < bucketCount; i++) {
62455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS);
62555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); }
62655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); }
62755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); }
62855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); }
62955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (operations != null) { pw.print(" op="); pw.print(operations[i]); }
63063d27a9233fed934340231f438493746084a681dJeff Sharkey            pw.println();
63175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
63263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
63363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.decreaseIndent();
63475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
63575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
63655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    public void dumpCheckin(PrintWriter pw) {
63755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print("d,");
63855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.print(bucketDuration / SECOND_IN_MILLIS);
63955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        pw.println();
64055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
64155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        for (int i = 0; i < bucketCount; i++) {
64255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print("b,");
64355a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(',');
64455a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(',');
64555a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(',');
64655a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(',');
64755a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(',');
64855a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); }
64955a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey            pw.println();
65055a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey        }
65155a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey    }
65255a442e58262e253df965d652bd8219c8d1e72d3Jeff Sharkey
653da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    public void writeToProto(ProtoOutputStream proto, long tag) {
654da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        final long start = proto.start(tag);
655da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
656da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
657da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
658da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        for (int i = 0; i < bucketCount; i++) {
659da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
660da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
661da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
662da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
663da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
664da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
665da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
666da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
667da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
668da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.end(startBucket);
669da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        }
670da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
671da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        proto.end(start);
672da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    }
673da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
674da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
675da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        if (array != null) {
676da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki            proto.write(tag, array[index]);
677da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki        }
678da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki    }
679da65a52f87ca1a31c9e01e99756e38d37d7e7202Makoto Onuki
68075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Override
68175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public String toString() {
68275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
68363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        dump(new IndentingPrintWriter(writer, "  "), false);
68475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return writer.toString();
68575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
68675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
68775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
688bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
68975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory createFromParcel(Parcel in) {
69075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory(in);
69175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
69275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
693bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
69475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory[] newArray(int size) {
69575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory[size];
69675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
69775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    };
69875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
69963d27a9233fed934340231f438493746084a681dJeff Sharkey    private static long getLong(long[] array, int i, long value) {
70063d27a9233fed934340231f438493746084a681dJeff Sharkey        return array != null ? array[i] : value;
70163d27a9233fed934340231f438493746084a681dJeff Sharkey    }
70263d27a9233fed934340231f438493746084a681dJeff Sharkey
70363d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void setLong(long[] array, int i, long value) {
70463d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] = value;
70563d27a9233fed934340231f438493746084a681dJeff Sharkey    }
70663d27a9233fed934340231f438493746084a681dJeff Sharkey
70763d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void addLong(long[] array, int i, long value) {
70863d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] += value;
70963d27a9233fed934340231f438493746084a681dJeff Sharkey    }
71063d27a9233fed934340231f438493746084a681dJeff Sharkey
71163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public int estimateResizeBuckets(long newBucketDuration) {
71263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return (int) (size() * getBucketDuration() / newBucketDuration);
71363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
71463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
715a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
716a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link DataInputStream} and
717a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * {@link DataOutputStream}, mostly dealing with writing partial arrays.
718a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
719a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class DataStreamUtils {
72063d27a9233fed934340231f438493746084a681dJeff Sharkey        @Deprecated
72163d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readFullLongArray(DataInputStream in) throws IOException {
722a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
7231f99a483e410811473b12d8efedd79c738df7af3Jeff Sharkey            if (size < 0) throw new ProtocolException("negative array size");
724a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
725a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
726a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
727a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
728a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
729a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
730a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
73163d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
73263d27a9233fed934340231f438493746084a681dJeff Sharkey         * Read variable-length {@link Long} using protobuf-style approach.
73363d27a9233fed934340231f438493746084a681dJeff Sharkey         */
73463d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long readVarLong(DataInputStream in) throws IOException {
73563d27a9233fed934340231f438493746084a681dJeff Sharkey            int shift = 0;
73663d27a9233fed934340231f438493746084a681dJeff Sharkey            long result = 0;
73763d27a9233fed934340231f438493746084a681dJeff Sharkey            while (shift < 64) {
73863d27a9233fed934340231f438493746084a681dJeff Sharkey                byte b = in.readByte();
73963d27a9233fed934340231f438493746084a681dJeff Sharkey                result |= (long) (b & 0x7F) << shift;
74063d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((b & 0x80) == 0)
74163d27a9233fed934340231f438493746084a681dJeff Sharkey                    return result;
74263d27a9233fed934340231f438493746084a681dJeff Sharkey                shift += 7;
74363d27a9233fed934340231f438493746084a681dJeff Sharkey            }
74463d27a9233fed934340231f438493746084a681dJeff Sharkey            throw new ProtocolException("malformed long");
74563d27a9233fed934340231f438493746084a681dJeff Sharkey        }
74663d27a9233fed934340231f438493746084a681dJeff Sharkey
74763d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
74863d27a9233fed934340231f438493746084a681dJeff Sharkey         * Write variable-length {@link Long} using protobuf-style approach.
74963d27a9233fed934340231f438493746084a681dJeff Sharkey         */
75063d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLong(DataOutputStream out, long value) throws IOException {
75163d27a9233fed934340231f438493746084a681dJeff Sharkey            while (true) {
75263d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((value & ~0x7FL) == 0) {
75363d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte((int) value);
75463d27a9233fed934340231f438493746084a681dJeff Sharkey                    return;
75563d27a9233fed934340231f438493746084a681dJeff Sharkey                } else {
75663d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte(((int) value & 0x7F) | 0x80);
75763d27a9233fed934340231f438493746084a681dJeff Sharkey                    value >>>= 7;
75863d27a9233fed934340231f438493746084a681dJeff Sharkey                }
75963d27a9233fed934340231f438493746084a681dJeff Sharkey            }
76063d27a9233fed934340231f438493746084a681dJeff Sharkey        }
76163d27a9233fed934340231f438493746084a681dJeff Sharkey
76263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readVarLongArray(DataInputStream in) throws IOException {
76363d27a9233fed934340231f438493746084a681dJeff Sharkey            final int size = in.readInt();
76463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
7651f99a483e410811473b12d8efedd79c738df7af3Jeff Sharkey            if (size < 0) throw new ProtocolException("negative array size");
76663d27a9233fed934340231f438493746084a681dJeff Sharkey            final long[] values = new long[size];
76763d27a9233fed934340231f438493746084a681dJeff Sharkey            for (int i = 0; i < values.length; i++) {
76863d27a9233fed934340231f438493746084a681dJeff Sharkey                values[i] = readVarLong(in);
76963d27a9233fed934340231f438493746084a681dJeff Sharkey            }
77063d27a9233fed934340231f438493746084a681dJeff Sharkey            return values;
77163d27a9233fed934340231f438493746084a681dJeff Sharkey        }
77263d27a9233fed934340231f438493746084a681dJeff Sharkey
77363d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
774a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throws IOException {
77563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
77663d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
77763d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
77863d27a9233fed934340231f438493746084a681dJeff Sharkey            }
779a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
780a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
781a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
782a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
783a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
78463d27a9233fed934340231f438493746084a681dJeff Sharkey                writeVarLong(out, values[i]);
785a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
78675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
78775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
78875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
789a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
790a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link Parcel} structures, mostly
791a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * dealing with writing partial arrays.
792a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
793a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class ParcelUtils {
794a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static long[] readLongArray(Parcel in) {
795a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
79663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
797a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
798a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
799a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
800a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
801a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
80275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
80375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
804a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static void writeLongArray(Parcel out, long[] values, int size) {
80563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
80663d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
80763d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
808a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
809a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
810a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
811a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
812a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
813a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
81463d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeLong(values[i]);
815a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
81675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
81775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
81875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
81975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey}
820