NetworkStatsHistory.java revision bfdd680ab44da173a4a39fcd6feccdebb9d1f855
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;
2963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport static com.android.internal.util.ArrayUtils.total;
30a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
3175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcel;
3275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport android.os.Parcelable;
3369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkeyimport android.util.MathUtils;
3475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
3563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
3663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
3775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.CharArrayWriter;
3875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataInputStream;
3975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.DataOutputStream;
4075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.io.IOException;
4161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.net.ProtocolException;
4275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeyimport java.util.Arrays;
4361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkeyimport java.util.Random;
4475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
4575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey/**
4675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Collection of historical network statistics, recorded into equally-sized
4775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * "buckets" in time. Internally it stores data in {@code long} series for more
4875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * efficient persistence.
4975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * <p>
5075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for
5175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is
5275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * sorted at all times.
5375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey *
5475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey * @hide
5575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey */
5675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkeypublic class NetworkStatsHistory implements Parcelable {
571b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey    private static final int VERSION_INIT = 1;
5863d27a9233fed934340231f438493746084a681dJeff Sharkey    private static final int VERSION_ADD_PACKETS = 2;
59558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private static final int VERSION_ADD_ACTIVE = 3;
6075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
61558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_ACTIVE_TIME = 0x01;
62558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_BYTES = 0x02;
63558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_RX_PACKETS = 0x04;
64558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_BYTES = 0x08;
65558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_TX_PACKETS = 0x10;
66558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    public static final int FIELD_OPERATIONS = 0x20;
67d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
6863d27a9233fed934340231f438493746084a681dJeff Sharkey    public static final int FIELD_ALL = 0xFFFFFFFF;
6963d27a9233fed934340231f438493746084a681dJeff Sharkey
7063d27a9233fed934340231f438493746084a681dJeff Sharkey    private long bucketDuration;
71d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private int bucketCount;
72d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] bucketStart;
73558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey    private long[] activeTime;
74d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] rxBytes;
75a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] rxPackets;
76d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    private long[] txBytes;
77a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    private long[] txPackets;
7863d27a9233fed934340231f438493746084a681dJeff Sharkey    private long[] operations;
7963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    private long totalBytes;
80d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
81d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public static class Entry {
8263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static final long UNKNOWN = -1;
8363d27a9233fed934340231f438493746084a681dJeff Sharkey
84d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long bucketDuration;
85558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long bucketStart;
86558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        public long activeTime;
87d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long rxBytes;
88a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long rxPackets;
89d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        public long txBytes;
90a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public long txPackets;
9163d27a9233fed934340231f438493746084a681dJeff Sharkey        public long operations;
92d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
9375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
94d2a458750e5a3d490af09cecb5c28370baf0a913Jeff Sharkey    public NetworkStatsHistory(long bucketDuration) {
9563d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, 10, FIELD_ALL);
964a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    }
974a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey
984a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize) {
9963d27a9233fed934340231f438493746084a681dJeff Sharkey        this(bucketDuration, initialSize, FIELD_ALL);
10063d27a9233fed934340231f438493746084a681dJeff Sharkey    }
10163d27a9233fed934340231f438493746084a681dJeff Sharkey
10263d27a9233fed934340231f438493746084a681dJeff Sharkey    public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) {
10375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        this.bucketDuration = bucketDuration;
1044a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketStart = new long[initialSize];
105558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize];
10663d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize];
10763d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize];
10863d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize];
10963d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
11063d27a9233fed934340231f438493746084a681dJeff Sharkey        if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
1114a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        bucketCount = 0;
11263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = 0;
11363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
11463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
11563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
11663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
11763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        recordEntireHistory(existing);
11875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
11975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
12075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(Parcel in) {
12175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketDuration = in.readLong();
12275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart = readLongArray(in);
123558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        activeTime = readLongArray(in);
124a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxBytes = readLongArray(in);
125a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        rxPackets = readLongArray(in);
126a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txBytes = readLongArray(in);
127a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        txPackets = readLongArray(in);
12863d27a9233fed934340231f438493746084a681dJeff Sharkey        operations = readLongArray(in);
12975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount = bucketStart.length;
13063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes = in.readLong();
13175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
13275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
133bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
13475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToParcel(Parcel out, int flags) {
13575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
13675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        writeLongArray(out, bucketStart, bucketCount);
137558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeLongArray(out, activeTime, bucketCount);
138d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, rxBytes, bucketCount);
139a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, rxPackets, bucketCount);
140d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        writeLongArray(out, txBytes, bucketCount);
141a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        writeLongArray(out, txPackets, bucketCount);
14263d27a9233fed934340231f438493746084a681dJeff Sharkey        writeLongArray(out, operations, bucketCount);
14363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        out.writeLong(totalBytes);
14475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
14575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
14675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public NetworkStatsHistory(DataInputStream in) throws IOException {
14775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final int version = in.readInt();
14861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        switch (version) {
1491b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey            case VERSION_INIT: {
15061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketDuration = in.readLong();
15163d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readFullLongArray(in);
15263d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readFullLongArray(in);
153a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                rxPackets = new long[bucketStart.length];
15463d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readFullLongArray(in);
155a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                txPackets = new long[bucketStart.length];
15663d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = new long[bucketStart.length];
15763d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketCount = bucketStart.length;
15863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
15963d27a9233fed934340231f438493746084a681dJeff Sharkey                break;
16063d27a9233fed934340231f438493746084a681dJeff Sharkey            }
161558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_PACKETS:
162558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            case VERSION_ADD_ACTIVE: {
16363d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketDuration = in.readLong();
16463d27a9233fed934340231f438493746084a681dJeff Sharkey                bucketStart = readVarLongArray(in);
165558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in)
166558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey                        : new long[bucketStart.length];
16763d27a9233fed934340231f438493746084a681dJeff Sharkey                rxBytes = readVarLongArray(in);
16863d27a9233fed934340231f438493746084a681dJeff Sharkey                rxPackets = readVarLongArray(in);
16963d27a9233fed934340231f438493746084a681dJeff Sharkey                txBytes = readVarLongArray(in);
17063d27a9233fed934340231f438493746084a681dJeff Sharkey                txPackets = readVarLongArray(in);
17163d27a9233fed934340231f438493746084a681dJeff Sharkey                operations = readVarLongArray(in);
17261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                bucketCount = bucketStart.length;
17363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey                totalBytes = total(rxBytes) + total(txBytes);
17461ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                break;
17561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
17661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            default: {
17761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey                throw new ProtocolException("unexpected version: " + version);
17861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            }
17961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
18075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
18175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
18275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void writeToStream(DataOutputStream out) throws IOException {
183558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        out.writeInt(VERSION_ADD_ACTIVE);
18475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        out.writeLong(bucketDuration);
18563d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, bucketStart, bucketCount);
186558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        writeVarLongArray(out, activeTime, bucketCount);
18763d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxBytes, bucketCount);
18863d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, rxPackets, bucketCount);
18963d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txBytes, bucketCount);
19063d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, txPackets, bucketCount);
19163d27a9233fed934340231f438493746084a681dJeff Sharkey        writeVarLongArray(out, operations, bucketCount);
19275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
19375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
194bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey    @Override
19575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public int describeContents() {
19675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return 0;
19775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
19875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
199d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public int size() {
200d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketCount;
201d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
202d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
203d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public long getBucketDuration() {
204d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return bucketDuration;
205d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
206d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
207434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getStart() {
208434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
209434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[0];
210434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
211434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MAX_VALUE;
212434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
213434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
214434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
215434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public long getEnd() {
216434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        if (bucketCount > 0) {
217434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return bucketStart[bucketCount - 1] + bucketDuration;
218434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        } else {
219434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            return Long.MIN_VALUE;
220434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        }
221434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
222434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
223d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    /**
22463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     * Return total bytes represented by this history.
22563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey     */
22663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public long getTotalBytes() {
22763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return totalBytes;
22863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
22963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
23063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    /**
23169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately before the
23269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
23369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
23469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexBefore(long time) {
23569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
23669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
23769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = (~index) - 1;
23869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
23969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index -= 1;
24069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
24169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
24269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
24369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
24469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
24569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * Return index of bucket that contains or is immediately after the
24669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     * requested time.
24769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey     */
24869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    public int getIndexAfter(long time) {
24969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
25069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        if (index < 0) {
25169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index = ~index;
25269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        } else {
25369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            index += 1;
25469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        }
25569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        return MathUtils.constrain(index, 0, bucketCount - 1);
25669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    }
25769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey
25869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey    /**
259d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     * Return specific stats entry.
260d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey     */
261d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    public Entry getValues(int i, Entry recycle) {
262d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
263d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketStart = bucketStart[i];
264d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        entry.bucketDuration = bucketDuration;
265558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = getLong(activeTime, i, UNKNOWN);
26663d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = getLong(rxBytes, i, UNKNOWN);
26763d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = getLong(rxPackets, i, UNKNOWN);
26863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = getLong(txBytes, i, UNKNOWN);
26963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = getLong(txPackets, i, UNKNOWN);
27063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = getLong(operations, i, UNKNOWN);
271d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey        return entry;
272d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey    }
273d37948f6ed1667d077e0e3a38808f42f981ddcc2Jeff Sharkey
27475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
27575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
27675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
27775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
278a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    @Deprecated
279a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, long rxBytes, long txBytes) {
280b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        recordData(start, end, new NetworkStats.Entry(
281b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L));
282a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    }
283a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
284a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
285a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Record that data traffic occurred in the given time range. Will
286a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * distribute across internal buckets, creating new buckets as needed.
287a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
288a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public void recordData(long start, long end, NetworkStats.Entry entry) {
28963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxBytes = entry.rxBytes;
29063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long rxPackets = entry.rxPackets;
29163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txBytes = entry.txBytes;
29263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long txPackets = entry.txPackets;
29363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        long operations = entry.operations;
29463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
29563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isNegative()) {
296a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            throw new IllegalArgumentException("tried recording negative data");
2971b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey        }
29863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        if (entry.isEmpty()) {
299367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey            return;
300367d15ab1a33b6159447fa8542d4fa8ff148371cJeff Sharkey        }
3011b5a2a96f793211bfbd39aa29cc41031dfa23950Jeff Sharkey
30275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create any buckets needed by this range
30375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        ensureBuckets(start, end);
30475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
30575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // distribute data usage into buckets
306a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        long duration = end - start;
30769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
30869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
30975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
31075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
31175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
31275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is older than record; we're finished
31375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd < start) break;
31475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // bucket is newer than record; keep looking
31575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curStart > end) continue;
31675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
31775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
318a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
319a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
320a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
32163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxBytes = rxBytes * overlap / duration;
32263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracRxPackets = rxPackets * overlap / duration;
32363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxBytes = txBytes * overlap / duration;
32463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracTxPackets = txPackets * overlap / duration;
32563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            final long fracOperations = operations * overlap / duration;
326a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
327558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            addLong(activeTime, i, overlap);
32863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
32963abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
33063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
33163abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
33263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            addLong(this.operations, i, fracOperations); operations -= fracOperations;
333a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
334a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            duration -= overlap;
33575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
33663abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
33763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        totalBytes += entry.rxBytes + entry.txBytes;
33875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
33975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
34075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
34119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Record an entire {@link NetworkStatsHistory} into this history. Usually
34219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * for combining together stats for external reporting.
34319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
34419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    public void recordEntireHistory(NetworkStatsHistory input) {
345a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
346b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
34719862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        for (int i = 0; i < input.bucketCount; i++) {
34819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long start = input.bucketStart[i];
34919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long end = start + input.bucketDuration;
350a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
35163d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = getLong(input.rxBytes, i, 0L);
35263d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = getLong(input.rxPackets, i, 0L);
35363d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = getLong(input.txBytes, i, 0L);
35463d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = getLong(input.txPackets, i, 0L);
35563d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = getLong(input.operations, i, 0L);
356a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
357a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            recordData(start, end, entry);
35819862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
35919862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
36019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
36119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
36275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Ensure that buckets exist for given time range, creating as needed.
36375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
36475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void ensureBuckets(long start, long end) {
36575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // normalize incoming range to bucket boundaries
36675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        start -= start % bucketDuration;
36775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        end += (bucketDuration - (end % bucketDuration)) % bucketDuration;
36875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
36975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (long now = start; now < end; now += bucketDuration) {
37075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // try finding existing bucket
37175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now);
37275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (index < 0) {
37375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                // bucket missing, create and insert
37475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey                insertBucket(~index, now);
37575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            }
37675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
37775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
37875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
37975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
38075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Insert new bucket at requested index and starting time.
38175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
38275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    private void insertBucket(int index, long start) {
38375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create more buckets when needed
3844a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey        if (bucketCount >= bucketStart.length) {
3854a97122ebf4d92a3f94402041729d77905e6c0c0Jeff Sharkey            final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
38675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOf(bucketStart, newLength);
387558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength);
38863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength);
38963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength);
39063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength);
39163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength);
39263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOf(operations, newLength);
39375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
39475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
39575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        // create gap when inserting bucket in middle
39675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (index < bucketCount) {
39775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int dstPos = index + 1;
39875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketCount - index;
39975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
40075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
401558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length);
40263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
40363d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length);
40463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length);
40563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length);
40663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) System.arraycopy(operations, index, operations, dstPos, length);
40775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
40875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
40975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketStart[index] = start;
410558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        setLong(activeTime, index, 0L);
41163d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxBytes, index, 0L);
41263d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(rxPackets, index, 0L);
41363d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txBytes, index, 0L);
41463d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(txPackets, index, 0L);
41563d27a9233fed934340231f438493746084a681dJeff Sharkey        setLong(operations, index, 0L);
41675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        bucketCount++;
41775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
41875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
41975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    /**
42075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     * Remove buckets older than requested cutoff.
42175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey     */
42263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    @Deprecated
42375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public void removeBucketsBefore(long cutoff) {
42475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        int i;
42575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        for (i = 0; i < bucketCount; i++) {
42675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curStart = bucketStart[i];
42775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final long curEnd = curStart + bucketDuration;
42875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
42975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // cutoff happens before or during this bucket; everything before
43075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            // this bucket should be removed.
43175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            if (curEnd > cutoff) break;
43275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
43375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
43475279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        if (i > 0) {
43575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            final int length = bucketStart.length;
43675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketStart = Arrays.copyOfRange(bucketStart, i, length);
437558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length);
43863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length);
43963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length);
44063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length);
44163d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
44263d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
44375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            bucketCount -= i;
44463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
44563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            // TODO: subtract removed values from totalBytes
44675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
44775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
44875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
44961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    /**
45019862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
45119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     * across buckets, so values may be rounded slightly.
45219862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey     */
453434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, Entry recycle) {
454434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return getValues(start, end, Long.MAX_VALUE, recycle);
455434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    }
456434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey
457434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    /**
458434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * Return interpolated data usage across the requested range. Interpolates
459434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     * across buckets, so values may be rounded slightly.
460434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey     */
461434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey    public Entry getValues(long start, long end, long now, Entry recycle) {
462434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        final Entry entry = recycle != null ? recycle : new Entry();
463434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        entry.bucketDuration = end - start;
464558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.bucketStart = start;
465558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey        entry.activeTime = activeTime != null ? 0 : UNKNOWN;
46663d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxBytes = rxBytes != null ? 0 : UNKNOWN;
46763d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.rxPackets = rxPackets != null ? 0 : UNKNOWN;
46863d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txBytes = txBytes != null ? 0 : UNKNOWN;
46963d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.txPackets = txPackets != null ? 0 : UNKNOWN;
47063d27a9233fed934340231f438493746084a681dJeff Sharkey        entry.operations = operations != null ? 0 : UNKNOWN;
47119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
47269b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        final int startIndex = getIndexAfter(end);
47369b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey        for (int i = startIndex; i >= 0; i--) {
47419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curStart = bucketStart[i];
47519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey            final long curEnd = curStart + bucketDuration;
47619862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
47734c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is older than request; we're finished
47834c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curEnd <= start) break;
47934c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            // bucket is newer than request; keep looking
48034c73acf88c8190b8cd51d8b8f2b9c22aa7f7941Jeff Sharkey            if (curStart >= end) continue;
48119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
482434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            // include full value for active buckets, otherwise only fractional
483434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey            final boolean activeBucket = curStart < now && curEnd > now;
48469b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            final long overlap;
48569b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            if (activeBucket) {
48669b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = bucketDuration;
48769b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            } else {
48869b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapEnd = curEnd < end ? curEnd : end;
48969b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                final long overlapStart = curStart > start ? curStart : start;
49069b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey                overlap = overlapEnd - overlapStart;
49169b0f63af2e3babc2e9f048c4682032a0c17d9d0Jeff Sharkey            }
492a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (overlap <= 0) continue;
493a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
494a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            // integer math each time is faster than floating point
495558a23200697d306b75750cf4612cf0717e73537Jeff Sharkey            if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration;
49663d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
49763d27a9233fed934340231f438493746084a681dJeff Sharkey            if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration;
49863d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration;
49963d27a9233fed934340231f438493746084a681dJeff Sharkey            if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration;
50063d27a9233fed934340231f438493746084a681dJeff Sharkey            if (operations != null) entry.operations += operations[i] * overlap / bucketDuration;
50119862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey        }
502434962e44ea93b1c4d216c55f636a435bf54aa54Jeff Sharkey        return entry;
50319862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    }
50419862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey
50519862bf5d058b6ab0c2979e7a5e0297dae6b170bJeff Sharkey    /**
50661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     * @deprecated only for temporary testing
50761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey     */
50861ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    @Deprecated
509293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public void generateRandom(long start, long end, long bytes) {
510293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final Random r = new Random();
511293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
512293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final float fractionRx = r.nextFloat();
513293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxBytes = (long) (bytes * fractionRx);
514293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txBytes = (long) (bytes * (1 - fractionRx));
515293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
516293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long rxPackets = rxBytes / 1024;
517293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long txPackets = txBytes / 1024;
518293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        final long operations = rxBytes / 2048;
519293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
520293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey        generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r);
521293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    }
522293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey
523293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    /**
524293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     * @deprecated only for temporary testing
525293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey     */
526293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    @Deprecated
52763d27a9233fed934340231f438493746084a681dJeff Sharkey    public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes,
528293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            long txPackets, long operations, Random r) {
52961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        ensureBuckets(start, end);
53061ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
531a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        final NetworkStats.Entry entry = new NetworkStats.Entry(
532b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey                IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
53304cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey        while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128
53404cd0e47dbc1e9769ac6f258c923d5b17fa57986Jeff Sharkey                || operations > 32) {
53561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey            final long curStart = randomLong(r, start, end);
536293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey            final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2);
53763d27a9233fed934340231f438493746084a681dJeff Sharkey
53863d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxBytes = randomLong(r, 0, rxBytes);
53963d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.rxPackets = randomLong(r, 0, rxPackets);
54063d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txBytes = randomLong(r, 0, txBytes);
54163d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.txPackets = randomLong(r, 0, txPackets);
54263d27a9233fed934340231f438493746084a681dJeff Sharkey            entry.operations = randomLong(r, 0, operations);
54363d27a9233fed934340231f438493746084a681dJeff Sharkey
54463d27a9233fed934340231f438493746084a681dJeff Sharkey            rxBytes -= entry.rxBytes;
54563d27a9233fed934340231f438493746084a681dJeff Sharkey            rxPackets -= entry.rxPackets;
54663d27a9233fed934340231f438493746084a681dJeff Sharkey            txBytes -= entry.txBytes;
54763d27a9233fed934340231f438493746084a681dJeff Sharkey            txPackets -= entry.txPackets;
54863d27a9233fed934340231f438493746084a681dJeff Sharkey            operations -= entry.operations;
549f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey
550f0ceede8fff5df24e5c98701d81c2b71eb138aa9Jeff Sharkey            recordData(curStart, curEnd, entry);
55161ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        }
55261ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
55361ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
554293779f9c63cbae0dde564449f0270b595593b0dJeff Sharkey    public static long randomLong(Random r, long start, long end) {
55561ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        return (long) (start + (r.nextFloat() * (end - start)));
55661ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey    }
55761ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey
55863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public void dump(IndentingPrintWriter pw, boolean fullHistory) {
55961ee0bbb5b87fb5c4c3dc219868d52743def3d2bJeff Sharkey        pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
56063abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.increaseIndent();
561350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
562350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
563350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        if (start > 0) {
56463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
565350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        }
566350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey
567350083e36b9db6062e165954403ef921ff3dfdadJeff Sharkey        for (int i = start; i < bucketCount; i++) {
56863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey            pw.print("bucketStart="); pw.print(bucketStart[i]);
56947eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); }
57047eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); }
57147eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); }
57247eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            if (txBytes != null) { pw.print(" txBytes="); pw.print(txBytes[i]); }
57347eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            if (txPackets != null) { pw.print(" txPackets="); pw.print(txPackets[i]); }
57447eb102b40cd1324d89816a7fb0fecd14fd7a408Jeff Sharkey            if (operations != null) { pw.print(" operations="); pw.print(operations[i]); }
57563d27a9233fed934340231f438493746084a681dJeff Sharkey            pw.println();
57675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
57763abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
57863abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        pw.decreaseIndent();
57975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
58075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
58175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    @Override
58275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public String toString() {
58375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        final CharArrayWriter writer = new CharArrayWriter();
58463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        dump(new IndentingPrintWriter(writer, "  "), false);
58575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        return writer.toString();
58675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
58775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
58875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
589bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
59075279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory createFromParcel(Parcel in) {
59175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory(in);
59275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
59375279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
594bfdd680ab44da173a4a39fcd6feccdebb9d1f855Jeff Sharkey        @Override
59575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        public NetworkStatsHistory[] newArray(int size) {
59675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey            return new NetworkStatsHistory[size];
59775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
59875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    };
59975279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
60063d27a9233fed934340231f438493746084a681dJeff Sharkey    private static long getLong(long[] array, int i, long value) {
60163d27a9233fed934340231f438493746084a681dJeff Sharkey        return array != null ? array[i] : value;
60263d27a9233fed934340231f438493746084a681dJeff Sharkey    }
60363d27a9233fed934340231f438493746084a681dJeff Sharkey
60463d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void setLong(long[] array, int i, long value) {
60563d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] = value;
60663d27a9233fed934340231f438493746084a681dJeff Sharkey    }
60763d27a9233fed934340231f438493746084a681dJeff Sharkey
60863d27a9233fed934340231f438493746084a681dJeff Sharkey    private static void addLong(long[] array, int i, long value) {
60963d27a9233fed934340231f438493746084a681dJeff Sharkey        if (array != null) array[i] += value;
61063d27a9233fed934340231f438493746084a681dJeff Sharkey    }
61163d27a9233fed934340231f438493746084a681dJeff Sharkey
61263abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    public int estimateResizeBuckets(long newBucketDuration) {
61363abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey        return (int) (size() * getBucketDuration() / newBucketDuration);
61463abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey    }
61563abc37356728c0575d6a62a203102ae6d97953bJeff Sharkey
616a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
617a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link DataInputStream} and
618a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * {@link DataOutputStream}, mostly dealing with writing partial arrays.
619a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
620a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class DataStreamUtils {
62163d27a9233fed934340231f438493746084a681dJeff Sharkey        @Deprecated
62263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readFullLongArray(DataInputStream in) throws IOException {
623a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
624a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
625a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
626a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
627a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
628a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
629a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        }
630a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey
63163d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
63263d27a9233fed934340231f438493746084a681dJeff Sharkey         * Read variable-length {@link Long} using protobuf-style approach.
63363d27a9233fed934340231f438493746084a681dJeff Sharkey         */
63463d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long readVarLong(DataInputStream in) throws IOException {
63563d27a9233fed934340231f438493746084a681dJeff Sharkey            int shift = 0;
63663d27a9233fed934340231f438493746084a681dJeff Sharkey            long result = 0;
63763d27a9233fed934340231f438493746084a681dJeff Sharkey            while (shift < 64) {
63863d27a9233fed934340231f438493746084a681dJeff Sharkey                byte b = in.readByte();
63963d27a9233fed934340231f438493746084a681dJeff Sharkey                result |= (long) (b & 0x7F) << shift;
64063d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((b & 0x80) == 0)
64163d27a9233fed934340231f438493746084a681dJeff Sharkey                    return result;
64263d27a9233fed934340231f438493746084a681dJeff Sharkey                shift += 7;
64363d27a9233fed934340231f438493746084a681dJeff Sharkey            }
64463d27a9233fed934340231f438493746084a681dJeff Sharkey            throw new ProtocolException("malformed long");
64563d27a9233fed934340231f438493746084a681dJeff Sharkey        }
64663d27a9233fed934340231f438493746084a681dJeff Sharkey
64763d27a9233fed934340231f438493746084a681dJeff Sharkey        /**
64863d27a9233fed934340231f438493746084a681dJeff Sharkey         * Write variable-length {@link Long} using protobuf-style approach.
64963d27a9233fed934340231f438493746084a681dJeff Sharkey         */
65063d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLong(DataOutputStream out, long value) throws IOException {
65163d27a9233fed934340231f438493746084a681dJeff Sharkey            while (true) {
65263d27a9233fed934340231f438493746084a681dJeff Sharkey                if ((value & ~0x7FL) == 0) {
65363d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte((int) value);
65463d27a9233fed934340231f438493746084a681dJeff Sharkey                    return;
65563d27a9233fed934340231f438493746084a681dJeff Sharkey                } else {
65663d27a9233fed934340231f438493746084a681dJeff Sharkey                    out.writeByte(((int) value & 0x7F) | 0x80);
65763d27a9233fed934340231f438493746084a681dJeff Sharkey                    value >>>= 7;
65863d27a9233fed934340231f438493746084a681dJeff Sharkey                }
65963d27a9233fed934340231f438493746084a681dJeff Sharkey            }
66063d27a9233fed934340231f438493746084a681dJeff Sharkey        }
66163d27a9233fed934340231f438493746084a681dJeff Sharkey
66263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static long[] readVarLongArray(DataInputStream in) throws IOException {
66363d27a9233fed934340231f438493746084a681dJeff Sharkey            final int size = in.readInt();
66463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
66563d27a9233fed934340231f438493746084a681dJeff Sharkey            final long[] values = new long[size];
66663d27a9233fed934340231f438493746084a681dJeff Sharkey            for (int i = 0; i < values.length; i++) {
66763d27a9233fed934340231f438493746084a681dJeff Sharkey                values[i] = readVarLong(in);
66863d27a9233fed934340231f438493746084a681dJeff Sharkey            }
66963d27a9233fed934340231f438493746084a681dJeff Sharkey            return values;
67063d27a9233fed934340231f438493746084a681dJeff Sharkey        }
67163d27a9233fed934340231f438493746084a681dJeff Sharkey
67263d27a9233fed934340231f438493746084a681dJeff Sharkey        public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
673a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throws IOException {
67463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
67563d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
67663d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
67763d27a9233fed934340231f438493746084a681dJeff Sharkey            }
678a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
679a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
680a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
681a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
682a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
68363d27a9233fed934340231f438493746084a681dJeff Sharkey                writeVarLong(out, values[i]);
684a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
68575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
68675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
68775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
688a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    /**
689a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * Utility methods for interacting with {@link Parcel} structures, mostly
690a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     * dealing with writing partial arrays.
691a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey     */
692a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey    public static class ParcelUtils {
693a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static long[] readLongArray(Parcel in) {
694a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final int size = in.readInt();
69563d27a9233fed934340231f438493746084a681dJeff Sharkey            if (size == -1) return null;
696a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            final long[] values = new long[size];
697a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < values.length; i++) {
698a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                values[i] = in.readLong();
699a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
700a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            return values;
70175279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
70275279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
703a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey        public static void writeLongArray(Parcel out, long[] values, int size) {
70463d27a9233fed934340231f438493746084a681dJeff Sharkey            if (values == null) {
70563d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeInt(-1);
70663d27a9233fed934340231f438493746084a681dJeff Sharkey                return;
707a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
708a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            if (size > values.length) {
709a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                throw new IllegalArgumentException("size larger than length");
710a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
711a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            out.writeInt(size);
712a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            for (int i = 0; i < size; i++) {
71363d27a9233fed934340231f438493746084a681dJeff Sharkey                out.writeLong(values[i]);
714a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            }
71575279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey        }
71675279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey    }
71775279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey
71875279904202357565cf5a1cb11148d01f42b4569Jeff Sharkey}
719