Merge changes from topic "stats-migration"

* changes:
  Skip PersistentIntTest on S- device
  Don't clobber existing history entries.
  Ensure NetworkStats migrated snapshot is identical
  [MS82.1] Support network stats data migration process
  Add a PersistentInt class.
This commit is contained in:
Natasha Lee
2022-06-01 03:03:02 +00:00
committed by Gerrit Code Review
9 changed files with 955 additions and 89 deletions

View File

@@ -865,6 +865,9 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
* Add association of the history with the specified key in this map.
*
* @param key The object used to identify a network, see {@link Key}.
* If history already exists for this key, then the passed-in history is appended
* to the previously-passed in history. The caller must ensure that the history
* passed-in timestamps are greater than all previously-passed-in timestamps.
* @param history {@link NetworkStatsHistory} instance associated to the given {@link Key}.
* @return The builder object.
*/
@@ -874,9 +877,21 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W
Objects.requireNonNull(key);
Objects.requireNonNull(history);
final List<Entry> historyEntries = history.getEntries();
final NetworkStatsHistory existing = mEntries.get(key);
final int size = historyEntries.size() + ((existing != null) ? existing.size() : 0);
final NetworkStatsHistory.Builder historyBuilder =
new NetworkStatsHistory.Builder(mBucketDurationMillis, historyEntries.size());
new NetworkStatsHistory.Builder(mBucketDurationMillis, size);
// TODO: this simply appends the entries to any entries that were already present in
// the builder, which requires the caller to pass in entries in order. We might be
// able to do better with something like recordHistory.
if (existing != null) {
for (Entry entry : existing.getEntries()) {
historyBuilder.addEntry(entry);
}
}
for (Entry entry : historyEntries) {
historyBuilder.addEntry(entry);
}

View File

@@ -32,6 +32,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -949,6 +950,25 @@ public final class NetworkStatsHistory implements Parcelable {
return writer.toString();
}
/**
* Same as "equals", but not actually called equals as this would affect public API behavior.
* @hide
*/
@Nullable
public boolean isSameAs(NetworkStatsHistory other) {
return bucketCount == other.bucketCount
&& Arrays.equals(bucketStart, other.bucketStart)
// Don't check activeTime since it can change on import due to the importer using
// recordHistory. It's also not exposed by the APIs or present in dumpsys or
// toString().
&& Arrays.equals(rxBytes, other.rxBytes)
&& Arrays.equals(rxPackets, other.rxPackets)
&& Arrays.equals(txBytes, other.txBytes)
&& Arrays.equals(txPackets, other.txPackets)
&& Arrays.equals(operations, other.operations)
&& totalBytes == other.totalBytes;
}
@UnsupportedAppUsage
public static final @android.annotation.NonNull Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
@Override
@@ -1116,14 +1136,44 @@ public final class NetworkStatsHistory implements Parcelable {
mOperations = new ArrayList<>(initialCapacity);
}
private void addToElement(List<Long> list, int pos, long value) {
list.set(pos, list.get(pos) + value);
}
/**
* Add an {@link Entry} into the {@link NetworkStatsHistory} instance.
*
* @param entry The target {@link Entry} object.
* @param entry The target {@link Entry} object. The entry timestamp must be greater than
* that of any previously-added entry.
* @return The builder object.
*/
@NonNull
public Builder addEntry(@NonNull Entry entry) {
final int lastBucket = mBucketStart.size() - 1;
final long lastBucketStart = (lastBucket != -1) ? mBucketStart.get(lastBucket) : 0;
// If last bucket has the same timestamp, modify it instead of adding another bucket.
// This allows callers to pass in the same bucket twice (e.g., to accumulate
// data over time), but still requires that entries must be sorted.
// The importer will do this in case a rotated file has the same timestamp as
// the previous file.
if (lastBucket != -1 && entry.bucketStart == lastBucketStart) {
addToElement(mActiveTime, lastBucket, entry.activeTime);
addToElement(mRxBytes, lastBucket, entry.rxBytes);
addToElement(mRxPackets, lastBucket, entry.rxPackets);
addToElement(mTxBytes, lastBucket, entry.txBytes);
addToElement(mTxPackets, lastBucket, entry.txPackets);
addToElement(mOperations, lastBucket, entry.operations);
return this;
}
// Inserting in the middle is prohibited for performance reasons.
if (entry.bucketStart <= lastBucketStart) {
throw new IllegalArgumentException("new bucket start " + entry.bucketStart
+ " must be greater than last bucket start " + lastBucketStart);
}
// Common case: add entries at the end of the list.
mBucketStart.add(entry.bucketStart);
mActiveTime.add(entry.activeTime);
mRxBytes.add(entry.rxBytes);