Growable NetworkStats object instead of builder.
NetworkStats now grows in place with arraycopy() instead of callers needing to know record count a priori. Better growth calculation for both NetworkStats and NetworkStatsHistory; 50% each time. Better estimates of buckets needed in calling services. Change-Id: I3adbffa0b7407612cc6349d9135a8b4eb63cd440
This commit is contained in:
@@ -23,6 +23,7 @@ import android.util.SparseBooleanArray;
|
||||
|
||||
import java.io.CharArrayWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
@@ -48,74 +49,60 @@ public class NetworkStats implements Parcelable {
|
||||
* generated.
|
||||
*/
|
||||
public final long elapsedRealtime;
|
||||
public final String[] iface;
|
||||
public final int[] uid;
|
||||
public final long[] rx;
|
||||
public final long[] tx;
|
||||
public int size;
|
||||
public String[] iface;
|
||||
public int[] uid;
|
||||
public long[] rx;
|
||||
public long[] tx;
|
||||
|
||||
// TODO: add fg/bg stats once reported by kernel
|
||||
|
||||
private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
|
||||
public NetworkStats(long elapsedRealtime, int initialSize) {
|
||||
this.elapsedRealtime = elapsedRealtime;
|
||||
this.iface = iface;
|
||||
this.uid = uid;
|
||||
this.rx = rx;
|
||||
this.tx = tx;
|
||||
this.size = 0;
|
||||
this.iface = new String[initialSize];
|
||||
this.uid = new int[initialSize];
|
||||
this.rx = new long[initialSize];
|
||||
this.tx = new long[initialSize];
|
||||
}
|
||||
|
||||
public NetworkStats(Parcel parcel) {
|
||||
elapsedRealtime = parcel.readLong();
|
||||
size = parcel.readInt();
|
||||
iface = parcel.createStringArray();
|
||||
uid = parcel.createIntArray();
|
||||
rx = parcel.createLongArray();
|
||||
tx = parcel.createLongArray();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private long mElapsedRealtime;
|
||||
private final String[] mIface;
|
||||
private final int[] mUid;
|
||||
private final long[] mRx;
|
||||
private final long[] mTx;
|
||||
|
||||
private int mIndex = 0;
|
||||
|
||||
public Builder(long elapsedRealtime, int size) {
|
||||
mElapsedRealtime = elapsedRealtime;
|
||||
mIface = new String[size];
|
||||
mUid = new int[size];
|
||||
mRx = new long[size];
|
||||
mTx = new long[size];
|
||||
public NetworkStats addEntry(String iface, int uid, long rx, long tx) {
|
||||
if (size >= this.iface.length) {
|
||||
final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
|
||||
this.iface = Arrays.copyOf(this.iface, newLength);
|
||||
this.uid = Arrays.copyOf(this.uid, newLength);
|
||||
this.rx = Arrays.copyOf(this.rx, newLength);
|
||||
this.tx = Arrays.copyOf(this.tx, newLength);
|
||||
}
|
||||
|
||||
public Builder addEntry(String iface, int uid, long rx, long tx) {
|
||||
mIface[mIndex] = iface;
|
||||
mUid[mIndex] = uid;
|
||||
mRx[mIndex] = rx;
|
||||
mTx[mIndex] = tx;
|
||||
mIndex++;
|
||||
return this;
|
||||
}
|
||||
this.iface[size] = iface;
|
||||
this.uid[size] = uid;
|
||||
this.rx[size] = rx;
|
||||
this.tx[size] = tx;
|
||||
size++;
|
||||
|
||||
public NetworkStats build() {
|
||||
if (mIndex != mIface.length) {
|
||||
throw new IllegalArgumentException("unexpected number of entries");
|
||||
}
|
||||
return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public int length() {
|
||||
// length is identical for all fields
|
||||
return iface.length;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first stats index that matches the requested parameters.
|
||||
*/
|
||||
public int findIndex(String iface, int uid) {
|
||||
final int length = length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
|
||||
return i;
|
||||
}
|
||||
@@ -195,9 +182,8 @@ public class NetworkStats implements Parcelable {
|
||||
}
|
||||
|
||||
// result will have our rows, and elapsed time between snapshots
|
||||
final int length = length();
|
||||
final NetworkStats.Builder result = new NetworkStats.Builder(deltaRealtime, length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
final NetworkStats result = new NetworkStats(deltaRealtime, size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
final String iface = this.iface[i];
|
||||
final int uid = this.uid[i];
|
||||
|
||||
@@ -221,7 +207,7 @@ public class NetworkStats implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
return result.build();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean equal(Object a, Object b) {
|
||||
@@ -255,6 +241,7 @@ public class NetworkStats implements Parcelable {
|
||||
/** {@inheritDoc} */
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(elapsedRealtime);
|
||||
dest.writeInt(size);
|
||||
dest.writeStringArray(iface);
|
||||
dest.writeIntArray(uid);
|
||||
dest.writeLongArray(rx);
|
||||
|
||||
@@ -53,11 +53,15 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
public long[] tx;
|
||||
|
||||
public NetworkStatsHistory(long bucketDuration) {
|
||||
this(bucketDuration, 10);
|
||||
}
|
||||
|
||||
public NetworkStatsHistory(long bucketDuration, int initialSize) {
|
||||
this.bucketDuration = bucketDuration;
|
||||
bucketStart = new long[0];
|
||||
rx = new long[0];
|
||||
tx = new long[0];
|
||||
bucketCount = bucketStart.length;
|
||||
bucketStart = new long[initialSize];
|
||||
rx = new long[initialSize];
|
||||
tx = new long[initialSize];
|
||||
bucketCount = 0;
|
||||
}
|
||||
|
||||
public NetworkStatsHistory(Parcel in) {
|
||||
@@ -168,8 +172,8 @@ public class NetworkStatsHistory implements Parcelable {
|
||||
*/
|
||||
private void insertBucket(int index, long start) {
|
||||
// create more buckets when needed
|
||||
if (bucketCount + 1 > bucketStart.length) {
|
||||
final int newLength = bucketStart.length + 10;
|
||||
if (bucketCount >= bucketStart.length) {
|
||||
final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
|
||||
bucketStart = Arrays.copyOf(bucketStart, newLength);
|
||||
rx = Arrays.copyOf(rx, newLength);
|
||||
tx = Arrays.copyOf(tx, newLength);
|
||||
|
||||
@@ -255,7 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
// combine all interfaces that match template
|
||||
final String subscriberId = getActiveSubscriberId();
|
||||
final NetworkStatsHistory combined = new NetworkStatsHistory(
|
||||
mSettings.getNetworkBucketDuration());
|
||||
mSettings.getNetworkBucketDuration(), estimateNetworkBuckets());
|
||||
for (InterfaceIdentity ident : mNetworkStats.keySet()) {
|
||||
final NetworkStatsHistory history = mNetworkStats.get(ident);
|
||||
if (ident.matchesTemplate(networkTemplate, subscriberId)) {
|
||||
@@ -297,9 +297,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, 1);
|
||||
final NetworkStats stats = new NetworkStats(end - start, 1);
|
||||
stats.addEntry(IFACE_ALL, UID_ALL, tx, tx);
|
||||
return stats.build();
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
ensureUidStatsLoadedLocked();
|
||||
|
||||
final int size = mUidStats.size();
|
||||
final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size);
|
||||
final NetworkStats stats = new NetworkStats(end - start, size);
|
||||
|
||||
long[] total = new long[2];
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -322,7 +322,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
total = history.getTotalData(start, end, total);
|
||||
stats.addEntry(IFACE_ALL, uid, total[0], total[1]);
|
||||
}
|
||||
return stats.build();
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,9 +510,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
// update when no existing, or when bucket duration changed
|
||||
NetworkStatsHistory updated = null;
|
||||
if (existing == null) {
|
||||
updated = new NetworkStatsHistory(bucketDuration);
|
||||
updated = new NetworkStatsHistory(bucketDuration, 10);
|
||||
} else if (existing.bucketDuration != bucketDuration) {
|
||||
updated = new NetworkStatsHistory(bucketDuration);
|
||||
updated = new NetworkStatsHistory(
|
||||
bucketDuration, estimateResizeBuckets(existing, bucketDuration));
|
||||
updated.recordEntireHistory(existing);
|
||||
}
|
||||
|
||||
@@ -531,9 +532,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
// update when no existing, or when bucket duration changed
|
||||
NetworkStatsHistory updated = null;
|
||||
if (existing == null) {
|
||||
updated = new NetworkStatsHistory(bucketDuration);
|
||||
updated = new NetworkStatsHistory(bucketDuration, 10);
|
||||
} else if (existing.bucketDuration != bucketDuration) {
|
||||
updated = new NetworkStatsHistory(bucketDuration);
|
||||
updated = new NetworkStatsHistory(
|
||||
bucketDuration, estimateResizeBuckets(existing, bucketDuration));
|
||||
updated.recordEntireHistory(existing);
|
||||
}
|
||||
|
||||
@@ -809,6 +811,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
return telephony.getSubscriberId();
|
||||
}
|
||||
|
||||
private int estimateNetworkBuckets() {
|
||||
return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
|
||||
}
|
||||
|
||||
private int estimateUidBuckets() {
|
||||
return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
|
||||
}
|
||||
|
||||
private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
|
||||
return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default external settings that read from {@link Settings.Secure}.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user