diff --git a/framework-t/Android.bp b/framework-t/Android.bp index deda74e328..0e1921a16e 100644 --- a/framework-t/Android.bp +++ b/framework-t/Android.bp @@ -57,6 +57,10 @@ java_defaults { "app-compat-annotations", "androidx.annotation_annotation", ], + static_libs: [ + // Cannot go to framework-connectivity because mid_sdk checks require 31. + "modules-utils-binary-xml", + ], impl_only_libs: [ // The build system will use framework-bluetooth module_current stubs, because // of sdk_version: "module_current" above. diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index b6f6dbb1cb..cb8328b5af 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -60,6 +60,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FileRotator; +import com.android.modules.utils.FastDataInput; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkStatsUtils; @@ -116,15 +117,28 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W private long mEndMillis; private long mTotalBytes; private boolean mDirty; + private final boolean mUseFastDataInput; /** * Construct a {@link NetworkStatsCollection} object. * - * @param bucketDuration duration of the buckets in this object, in milliseconds. + * @param bucketDurationMillis duration of the buckets in this object, in milliseconds. * @hide */ public NetworkStatsCollection(long bucketDurationMillis) { + this(bucketDurationMillis, false /* useFastDataInput */); + } + + /** + * Construct a {@link NetworkStatsCollection} object. + * + * @param bucketDurationMillis duration of the buckets in this object, in milliseconds. + * @param useFastDataInput true if using {@link FastDataInput} is preferred. Otherwise, false. + * @hide + */ + public NetworkStatsCollection(long bucketDurationMillis, boolean useFastDataInput) { mBucketDurationMillis = bucketDurationMillis; + mUseFastDataInput = useFastDataInput; reset(); } @@ -483,7 +497,11 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** @hide */ @Override public void read(InputStream in) throws IOException { - read((DataInput) new DataInputStream(in)); + if (mUseFastDataInput) { + read(FastDataInput.obtain(in)); + } else { + read((DataInput) new DataInputStream(in)); + } } private void read(DataInput in) throws IOException { diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index 3da15856b7..5f9b65c651 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -79,6 +79,7 @@ public class NetworkStatsRecorder { private final long mBucketDuration; private final boolean mOnlyTags; private final boolean mWipeOnError; + private final boolean mUseFastDataInput; private long mPersistThresholdBytes = 2 * MB_IN_BYTES; private NetworkStats mLastSnapshot; @@ -104,6 +105,7 @@ public class NetworkStatsRecorder { mBucketDuration = YEAR_IN_MILLIS; mOnlyTags = false; mWipeOnError = true; + mUseFastDataInput = false; mPending = null; mSinceBoot = new NetworkStatsCollection(mBucketDuration); @@ -116,7 +118,7 @@ public class NetworkStatsRecorder { */ public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags, - boolean wipeOnError) { + boolean wipeOnError, boolean useFastDataInput) { mRotator = Objects.requireNonNull(rotator, "missing FileRotator"); mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver"); mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager"); @@ -125,6 +127,7 @@ public class NetworkStatsRecorder { mBucketDuration = bucketDuration; mOnlyTags = onlyTags; mWipeOnError = wipeOnError; + mUseFastDataInput = useFastDataInput; mPending = new NetworkStatsCollection(bucketDuration); mSinceBoot = new NetworkStatsCollection(bucketDuration); @@ -195,8 +198,12 @@ public class NetworkStatsRecorder { } private NetworkStatsCollection loadLocked(long start, long end) { - if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie); - final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration); + if (LOGD) { + Log.d(TAG, "loadLocked() reading from disk for " + mCookie + + " useFastDataInput: " + mUseFastDataInput); + } + final NetworkStatsCollection res = + new NetworkStatsCollection(mBucketDuration, mUseFastDataInput); try { mRotator.readMatching(res, start, end); res.recordCollection(mPending); diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 2c9f30c8f7..ad83e7f6c8 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -969,7 +969,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new NetworkStatsRecorder(new FileRotator( baseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags, - wipeOnError); + wipeOnError, false /* useFastDataInput */); } @GuardedBy("mStatsLock") diff --git a/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt b/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt index 585157fa8f..c3ea9f40a9 100644 --- a/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt +++ b/tests/benchmark/src/android/net/netstats/benchmarktests/NetworkStatsTest.kt @@ -133,7 +133,16 @@ class NetworkStatsTest { } @Test - fun testReadFromRecorder_manyUids() { + fun testReadFromRecorder_manyUids_useDataInput() { + doTestReadFromRecorder_manyUids(useFastDataInput = false) + } + + @Test + fun testReadFromRecorder_manyUids_useFastDataInput() { + doTestReadFromRecorder_manyUids(useFastDataInput = true) + } + + fun doTestReadFromRecorder_manyUids(useFastDataInput: Boolean) { val mockObserver = mock>() val mockDropBox = mock() testFilesAssets.forEach { @@ -146,7 +155,8 @@ class NetworkStatsTest { PREFIX_UID, UID_COLLECTION_BUCKET_DURATION_MS, false /* includeTags */, - false /* wipeOnError */ + false /* wipeOnError */, + useFastDataInput /* useFastDataInput */ ) recorder.orLoadCompleteLocked } diff --git a/tests/unit/java/android/net/NetworkStatsCollectionTest.java b/tests/unit/java/android/net/NetworkStatsCollectionTest.java index a6e9e9579a..81557f85c5 100644 --- a/tests/unit/java/android/net/NetworkStatsCollectionTest.java +++ b/tests/unit/java/android/net/NetworkStatsCollectionTest.java @@ -64,6 +64,7 @@ import libcore.io.Streams; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -90,7 +91,8 @@ import java.util.Set; @SmallTest @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available public class NetworkStatsCollectionTest { - + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); private static final String TEST_FILE = "test.bin"; private static final String TEST_IMSI = "310260000000000"; private static final int TEST_SUBID = 1; @@ -199,6 +201,33 @@ public class NetworkStatsCollectionTest { 77017831L, 100995L, 35436758L, 92344L); } + private InputStream getUidInputStreamFromRes(int uidRes) throws Exception { + final File testFile = + new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE); + stageFile(uidRes, testFile); + + final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS); + collection.readLegacyUid(testFile, true); + + // now export into a unified format + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + collection.write(bos); + return new ByteArrayInputStream(bos.toByteArray()); + } + + @Test + public void testFastDataInputRead() throws Exception { + final NetworkStatsCollection legacyCollection = + new NetworkStatsCollection(30 * MINUTE_IN_MILLIS, false /* useFastDataInput */); + final NetworkStatsCollection fastReadCollection = + new NetworkStatsCollection(30 * MINUTE_IN_MILLIS, true /* useFastDataInput */); + final InputStream bis = getUidInputStreamFromRes(R.raw.netstats_uid_v4); + legacyCollection.read(bis); + bis.reset(); + fastReadCollection.read(bis); + assertCollectionEntries(legacyCollection.getEntries(), fastReadCollection); + } + @Test public void testStartEndAtomicBuckets() throws Exception { final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS); diff --git a/tests/unit/java/android/net/NetworkStatsRecorderTest.java b/tests/unit/java/android/net/NetworkStatsRecorderTest.java index fad11a3ff7..e8f853e37a 100644 --- a/tests/unit/java/android/net/NetworkStatsRecorderTest.java +++ b/tests/unit/java/android/net/NetworkStatsRecorderTest.java @@ -64,7 +64,8 @@ public final class NetworkStatsRecorderTest { private NetworkStatsRecorder buildRecorder(FileRotator rotator, boolean wipeOnError) { return new NetworkStatsRecorder(rotator, mObserver, mDropBox, TEST_PREFIX, - HOUR_IN_MILLIS, false /* includeTags */, wipeOnError); + HOUR_IN_MILLIS, false /* includeTags */, wipeOnError, + false /* useFastDataInput */); } @Test diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java index 5c7fdb6d12..19216a73cb 100644 --- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java @@ -2230,7 +2230,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { final DropBoxManager dropBox = mock(DropBoxManager.class); return new NetworkStatsRecorder(new FileRotator( directory, prefix, config.rotateAgeMillis, config.deleteAgeMillis), - observer, dropBox, prefix, config.bucketDuration, includeTags, wipeOnError); + observer, dropBox, prefix, config.bucketDuration, includeTags, wipeOnError, + false /* useFastDataInput */); } private NetworkStatsCollection getLegacyCollection(String prefix, boolean includeTags) {