From e9eb8e2b8a3589825d86c598ec4653fe3b02bbaa Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 21 Aug 2025 16:37:45 +0800 Subject: [PATCH] Remove service-side TrafficStats rate limit cache The service-side TrafficStats rate limit cache is no longer needed as client-side caching is now solely responsible for rate-limiting traffic stats queries. This commit removes: - The `clearTrafficStatsRateLimitCaches` AIDL method. - The service-side cache implementation, including member variables and logic within `NetworkStatsService`. - Related feature flags and constants used for the service-side cache. - All unit tests specifically for the service-side cache. This simplifies the overall traffic statistics caching architecture by centralizing rate-limiting responsibility on the client side. Flag: EXEMPT refactoring Test: atest ConnectivityCoverageTests --test-filter '.*NetworkStats.*' --update-device Test: atest ConnectivityCoverageTests --test-filter '.*TrafficStats.*' --update-device Fix: 428098676 Fix: 428097311 Change-Id: I41cbb80a52f04dcf387c3352677a91cb692ffe73 --- .../src/android/net/INetworkStatsService.aidl | 3 - framework-t/src/android/net/TrafficStats.java | 5 - .../server/net/NetworkStatsService.java | 142 +---------------- .../net/TrafficStatsRateLimitCache.java | 115 -------------- .../server/net/NetworkStatsServiceTest.java | 119 +------------- .../net/TrafficStatsRateLimitCacheTest.kt | 150 ------------------ 6 files changed, 9 insertions(+), 525 deletions(-) delete mode 100644 service-t/src/com/android/server/net/TrafficStatsRateLimitCache.java delete mode 100644 tests/unit/java/com/android/server/net/TrafficStatsRateLimitCacheTest.kt diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl index b459a13d8f..a02d8d03a6 100644 --- a/framework-t/src/android/net/INetworkStatsService.aidl +++ b/framework-t/src/android/net/INetworkStatsService.aidl @@ -103,9 +103,6 @@ interface INetworkStatsService { */ void setStatsProviderWarningAndLimitAsync(String iface, long warning, long limit); - /** Clear TrafficStats rate-limit caches. */ - void clearTrafficStatsRateLimitCaches(); - /** Get rate-limit cache config. */ TrafficStatsRateLimitCacheConfig getRateLimitCacheConfig(); } diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index 868033ad5b..2eebfbfa57 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -892,11 +892,6 @@ public class TrafficStats { if (uidCache != null) { uidCache.clear(); } - try { - getStatsService().clearTrafficStatsRateLimitCaches(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } } /** diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 7dd7c5d760..c82955f44f 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -16,7 +16,6 @@ package com.android.server.net; -import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; @@ -308,10 +307,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { static final String TRAFFIC_STATS_CACHE_EXPIRY_DURATION_NAME = "trafficstats_cache_expiry_duration_ms"; - static final String TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES_NAME = + static final String TRAFFIC_STATS_CACHE_MAX_ENTRIES_NAME = "trafficstats_cache_max_entries"; static final int DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS = 1000; - static final int DEFAULT_TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES = 400; + static final int DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES = 400; /** * The delay time between to network stats update intents. * Added to fix intent spams (b/343844995) @@ -489,25 +488,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private long mLatestNetworkStatsUpdatedBroadcastScheduledTime = Long.MIN_VALUE; - @Nullable - private final TrafficStatsRateLimitCache mTrafficStatsTotalCache; - @Nullable - private final TrafficStatsRateLimitCache mTrafficStatsIfaceCache; - @Nullable - private final TrafficStatsRateLimitCache mTrafficStatsUidCache; // A feature flag to control whether the client-side rate limit cache should be enabled. @VisibleForTesting public static final String TRAFFICSTATS_CLIENT_RATE_LIMIT_CACHE_ENABLED_FLAG = "trafficstats_client_rate_limit_cache_enabled_flag"; @VisibleForTesting public static final String STORE_TRANSPORT_TYPES = "store_transport_types"; - static final String TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG = - "trafficstats_rate_limit_cache_enabled_flag"; static final String BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG = "broadcast_network_stats_updated_rate_limit_enabled_flag"; - private final boolean mIsTrafficStatsServiceRateLimitCacheEnabled; - private final int mTrafficStatsRateLimitCacheExpiryDuration; - private final int mTrafficStatsServiceRateLimitCacheMaxEntries; private final TrafficStatsRateLimitCacheConfig mTrafficStatsRateLimitCacheClientSideConfig; private final boolean mBroadcastNetworkStatsUpdatedRateLimitEnabled; @@ -706,32 +694,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mTrafficStatsRateLimitCacheClientSideConfig = mDeps.getTrafficStatsRateLimitCacheClientSideConfig(mContext); - // If the client side cache feature is enabled, disable the service side - // cache unconditionally. - mIsTrafficStatsServiceRateLimitCacheEnabled = - mDeps.isTrafficStatsServiceRateLimitCacheEnabled(mContext, - mTrafficStatsRateLimitCacheClientSideConfig.isCacheEnabled); mBroadcastNetworkStatsUpdatedRateLimitEnabled = mDeps.enabledBroadcastNetworkStatsUpdatedRateLimiting(mContext); - mTrafficStatsRateLimitCacheExpiryDuration = - mDeps.getTrafficStatsRateLimitCacheExpiryDuration(); - mTrafficStatsServiceRateLimitCacheMaxEntries = - mDeps.getTrafficStatsServiceRateLimitCacheMaxEntries(); - if (mIsTrafficStatsServiceRateLimitCacheEnabled) { - mTrafficStatsTotalCache = new TrafficStatsRateLimitCache(mClock, - mTrafficStatsRateLimitCacheExpiryDuration, - mTrafficStatsServiceRateLimitCacheMaxEntries); - mTrafficStatsIfaceCache = new TrafficStatsRateLimitCache(mClock, - mTrafficStatsRateLimitCacheExpiryDuration, - mTrafficStatsServiceRateLimitCacheMaxEntries); - mTrafficStatsUidCache = new TrafficStatsRateLimitCache(mClock, - mTrafficStatsRateLimitCacheExpiryDuration, - mTrafficStatsServiceRateLimitCacheMaxEntries); - } else { - mTrafficStatsTotalCache = null; - mTrafficStatsIfaceCache = null; - mTrafficStatsUidCache = null; - } mSkDestroyListener = mDeps.makeSkDestroyListener((message) -> { final StructInetDiagSockId sockId = message.inetDiagMsg.id; @@ -1012,52 +976,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS)) .setMaxEntries(getDeviceConfigPropertyInt( NAMESPACE_TETHERING, - TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES_NAME, - DEFAULT_TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES)) + TRAFFIC_STATS_CACHE_MAX_ENTRIES_NAME, + DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES)) .build(); return config; } - /** - * Determines whether the service-side rate-limiting cache is enabled. - * - * The cache is enabled for devices running Android V+ or apps targeting SDK V+ - * if the `TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG` feature flag - * is enabled and client-side caching is disabled. - * - * This method should only be called once in the constructor, - * to ensure that the code does not need to deal with flag values changing at runtime. - */ - public boolean isTrafficStatsServiceRateLimitCacheEnabled(@NonNull Context ctx, - boolean clientCacheEnabled) { - return !clientCacheEnabled && DeviceConfigUtils.isTetheringFeatureNotChickenedOut( - ctx, TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG); - } - - /** - * Get TrafficStats rate-limit cache expiry. - * - * This method should only be called once in the constructor, - * to ensure that the code does not need to deal with flag values changing at runtime. - */ - public int getTrafficStatsRateLimitCacheExpiryDuration() { - return getDeviceConfigPropertyInt( - NAMESPACE_TETHERING, TRAFFIC_STATS_CACHE_EXPIRY_DURATION_NAME, - DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS); - } - - /** - * Get TrafficStats service side rate-limit cache max entries. - * - * This method should only be called once in the constructor, - * to ensure that the code does not need to deal with flag values changing at runtime. - */ - public int getTrafficStatsServiceRateLimitCacheMaxEntries() { - return getDeviceConfigPropertyInt( - NAMESPACE_TETHERING, TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES_NAME, - DEFAULT_TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES); - } - /** * Wrapper method for {@link CompatChanges#isChangeEnabled(long, int)} */ @@ -2207,20 +2131,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { || mDeps.isChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, callingUid)); } - /** - * Determines whether to use the service-side cache for traffic stats rate limiting. - * - * This is based on the cache enabled feature flag. If enabled, the service-side cache - * is used for V+ devices or callers with V+ target sdk. - * - * @param callingUid The UID of the app making the request. - * @return True if the service-side cache should be used, false otherwise. - */ - private boolean useServiceSideCache(int callingUid) { - return mIsTrafficStatsServiceRateLimitCacheEnabled && (SdkLevel.isAtLeastV() - || mDeps.isChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, callingUid)); - } - @Nullable @Override public StatsResult getUidStats(int uid) { @@ -2228,13 +2138,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { return null; } - final NetworkStats.Entry entry; - if (useServiceSideCache(callingUid)) { - entry = mTrafficStatsUidCache.getOrCompute(IFACE_ALL, uid, - () -> mDeps.nativeGetUidStat(uid)); - } else entry = mDeps.nativeGetUidStat(uid); - - return getStatsResultFromEntryOrNull(entry); + return getStatsResultFromEntryOrNull(mDeps.nativeGetUidStat(uid)); } @Nullable @@ -2255,14 +2159,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public StatsResult getIfaceStats(@NonNull String iface) { Objects.requireNonNull(iface); - - final NetworkStats.Entry entry; - if (useServiceSideCache(Binder.getCallingUid())) { - entry = mTrafficStatsIfaceCache.getOrCompute(iface, UID_ALL, - () -> getIfaceStatsInternal(iface)); - } else entry = getIfaceStatsInternal(iface); - - return getStatsResultFromEntryOrNull(entry); + return getStatsResultFromEntryOrNull(getIfaceStatsInternal(iface)); } @Nullable @@ -2284,23 +2181,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Nullable @Override public StatsResult getTotalStats() { - final NetworkStats.Entry entry; - if (useServiceSideCache(Binder.getCallingUid())) { - entry = mTrafficStatsTotalCache.getOrCompute( - IFACE_ALL, UID_ALL, () -> getTotalStatsInternal()); - } else entry = getTotalStatsInternal(); - - return getStatsResultFromEntryOrNull(entry); - } - - @Override - public void clearTrafficStatsRateLimitCaches() { - PermissionUtils.enforceNetworkStackPermissionOr(mContext, NETWORK_SETTINGS); - if (mIsTrafficStatsServiceRateLimitCacheEnabled) { - mTrafficStatsUidCache.clear(); - mTrafficStatsIfaceCache.clear(); - mTrafficStatsTotalCache.clear(); - } + return getStatsResultFromEntryOrNull(getTotalStatsInternal()); } @Override @@ -3084,15 +2965,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (IOException e) { pw.println("(failed to dump FastDataInput counters)"); } - pw.print("trafficstats.service.cache.isenabled", - mIsTrafficStatsServiceRateLimitCacheEnabled); - pw.println(); - pw.print(TRAFFIC_STATS_CACHE_EXPIRY_DURATION_NAME, - mTrafficStatsRateLimitCacheExpiryDuration); - pw.println(); - pw.print(TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES_NAME, - mTrafficStatsServiceRateLimitCacheMaxEntries); - pw.println(); pw.print("trafficstats.client.cache.config", mTrafficStatsRateLimitCacheClientSideConfig); pw.println(); diff --git a/service-t/src/com/android/server/net/TrafficStatsRateLimitCache.java b/service-t/src/com/android/server/net/TrafficStatsRateLimitCache.java deleted file mode 100644 index 4f99d1b361..0000000000 --- a/service-t/src/com/android/server/net/TrafficStatsRateLimitCache.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.NetworkStats; - -import com.android.net.module.util.LruCacheWithExpiry; - -import java.time.Clock; -import java.util.Objects; -import java.util.function.Supplier; - -/** - * A thread-safe cache for storing and retrieving {@link NetworkStats.Entry} objects, - * with an adjustable expiry duration to manage data freshness. - * - * @deprecated Use {@link LruCacheWithExpiry} instead. - */ -// TODO: Remove this when service side rate limit cache solution is removed. -class TrafficStatsRateLimitCache extends - LruCacheWithExpiry { - - /** - * Constructs a new {@link TrafficStatsRateLimitCache} with the specified expiry duration. - * - * @param clock The {@link Clock} to use for determining timestamps. - * @param expiryDurationMs The expiry duration in milliseconds. - * @param maxSize Maximum number of entries. - */ - TrafficStatsRateLimitCache(@NonNull Clock clock, long expiryDurationMs, int maxSize) { - super(()-> clock.millis(), expiryDurationMs, maxSize, it -> !it.isEmpty()); - } - - public static class TrafficStatsCacheKey { - @Nullable - private final String mIface; - private final int mUid; - - TrafficStatsCacheKey(@Nullable String iface, int uid) { - this.mIface = iface; - this.mUid = uid; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof TrafficStatsCacheKey)) return false; - TrafficStatsCacheKey that = (TrafficStatsCacheKey) o; - return mUid == that.mUid && Objects.equals(mIface, that.mIface); - } - - @Override - public int hashCode() { - return Objects.hash(mIface, mUid); - } - } - - /** - * Retrieves a {@link NetworkStats.Entry} from the cache, associated with the given key. - * - * @param iface The interface name to include in the cache key. Null if not applicable. - * @param uid The UID to include in the cache key. {@code UID_ALL} if not applicable. - * @return The cached {@link NetworkStats.Entry}, or null if not found or expired. - */ - @Nullable - NetworkStats.Entry get(String iface, int uid) { - return super.get(new TrafficStatsCacheKey(iface, uid)); - } - - /** - * Retrieves a {@link NetworkStats.Entry} from the cache, associated with the given key. - * If the entry is not found in the cache or has expired, computes it using the provided - * {@code supplier} and stores the result in the cache. - * - * @param iface The interface name to include in the cache key. {@code IFACE_ALL} - * if not applicable. - * @param uid The UID to include in the cache key. {@code UID_ALL} if not applicable. - * @param supplier The {@link Supplier} to compute the {@link NetworkStats.Entry} if not found. - * @return The cached or computed {@link NetworkStats.Entry}, or null if not found, expired, - * or if the {@code supplier} returns null. - */ - @Nullable - NetworkStats.Entry getOrCompute(String iface, int uid, - @NonNull Supplier supplier) { - return super.getOrCompute(new TrafficStatsCacheKey(iface, uid), supplier); - } - - /** - * Stores a {@link NetworkStats.Entry} in the cache, associated with the given key. - * - * @param iface The interface name to include in the cache key. Null if not applicable. - * @param uid The UID to include in the cache key. {@code UID_ALL} if not applicable. - * @param entry The {@link NetworkStats.Entry} to store in the cache. - */ - void put(String iface, int uid, @NonNull final NetworkStats.Entry entry) { - super.put(new TrafficStatsCacheKey(iface, uid), entry); - } - -} diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java index 74073ad09c..9ab7e3355d 100644 --- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java @@ -73,14 +73,13 @@ import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_PO import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; import static com.android.server.net.NetworkStatsService.BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG; import static com.android.server.net.NetworkStatsService.DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS; -import static com.android.server.net.NetworkStatsService.DEFAULT_TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES; +import static com.android.server.net.NetworkStatsService.DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES; import static com.android.server.net.NetworkStatsService.NETSTATS_FASTDATAINPUT_FALLBACKS_COUNTER_NAME; import static com.android.server.net.NetworkStatsService.NETSTATS_FASTDATAINPUT_SUCCESSES_COUNTER_NAME; import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME; import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME; import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME; import static com.android.server.net.NetworkStatsService.TRAFFICSTATS_CLIENT_RATE_LIMIT_CACHE_ENABLED_FLAG; -import static com.android.server.net.NetworkStatsService.TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -130,7 +129,6 @@ import android.net.TestNetworkSpecifier; import android.net.TetherStatsParcel; import android.net.TetheringManager; import android.net.UnderlyingNetworkInfo; -import android.net.netstats.StatsResult; import android.net.netstats.TrafficStatsRateLimitCacheConfig; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.wifi.WifiInfo; @@ -625,29 +623,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { return mFeatureFlags.getOrDefault(feature, true); } - @Override - public boolean isTrafficStatsServiceRateLimitCacheEnabled(Context ctx, - boolean isClientCacheEnabled) { - return !isClientCacheEnabled && mFeatureFlags.getOrDefault( - TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG, false); - } - @Override public boolean enabledBroadcastNetworkStatsUpdatedRateLimiting(Context ctx) { return mFeatureFlags.getOrDefault( BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG, true); } - @Override - public int getTrafficStatsRateLimitCacheExpiryDuration() { - return DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS; - } - - @Override - public int getTrafficStatsServiceRateLimitCacheMaxEntries() { - return DEFAULT_TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES; - } - @Override public TrafficStatsRateLimitCacheConfig getTrafficStatsRateLimitCacheClientSideConfig( @NonNull Context ctx) { @@ -656,7 +637,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { .setIsCacheEnabled(mFeatureFlags.getOrDefault( TRAFFICSTATS_CLIENT_RATE_LIMIT_CACHE_ENABLED_FLAG, false)) .setExpiryDurationMs(DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS) - .setMaxEntries(DEFAULT_TRAFFIC_STATS_SERVICE_CACHE_MAX_ENTRIES) + .setMaxEntries(DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES) .build(); return config; } @@ -2573,102 +2554,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { assertTrue(mService.getRateLimitCacheConfig().isCacheEnabled); } - @FeatureFlag(name = TRAFFICSTATS_CLIENT_RATE_LIMIT_CACHE_ENABLED_FLAG) - @FeatureFlag(name = TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG) - @Test - public void testTrafficStatsRateLimitCache_clientCacheEnabledDisableServiceCache() - throws Exception { - mDeps.setChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, true); - doTestTrafficStatsRateLimitCache(false /* expectCached */); - } - - @FeatureFlag(name = TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG, enabled = false) - @Test - public void testTrafficStatsRateLimitCache_disabledWithCompatChangeEnabled() throws Exception { - mDeps.setChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, true); - doTestTrafficStatsRateLimitCache(false /* expectCached */); - } - - @FeatureFlag(name = TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG) - @Test - public void testTrafficStatsRateLimitCache_enabledWithCompatChangeEnabled() throws Exception { - mDeps.setChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, true); - doTestTrafficStatsRateLimitCache(true /* expectCached */); - } - - @FeatureFlag(name = TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG, enabled = false) - @Test - public void testTrafficStatsRateLimitCache_disabledWithCompatChangeDisabled() throws Exception { - mDeps.setChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, false); - doTestTrafficStatsRateLimitCache(false /* expectCached */); - } - - @FeatureFlag(name = TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG) - @DevSdkIgnoreRule.IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) - @Test - public void testTrafficStatsRateLimitCache_enabledWithCompatChangeDisabled_belowV() - throws Exception { - mDeps.setChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, false); - doTestTrafficStatsRateLimitCache(false /* expectCached */); - } - - @FeatureFlag(name = TRAFFICSTATS_SERVICE_RATE_LIMIT_CACHE_ENABLED_FLAG) - @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) - @Test - public void testTrafficStatsRateLimitCache_enabledWithCompatChangeDisabled_vOrAbove() - throws Exception { - mDeps.setChangeEnabled(ENABLE_TRAFFICSTATS_RATE_LIMIT_CACHE, false); - doTestTrafficStatsRateLimitCache(true /* expectCached */); - } - - private void doTestTrafficStatsRateLimitCache(boolean expectCached) throws Exception { - mockDefaultSettings(); - // Calling uid is not injected into the service, use the real uid to pass the caller check. - final int myUid = Process.myUid(); - mockTrafficStatsValues(64L, 3L, 1024L, 8L); - assertTrafficStatsValues(TEST_IFACE, myUid, 64L, 3L, 1024L, 8L); - - // Verify the values are cached. - incrementCurrentTime(DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS / 2); - mockTrafficStatsValues(65L, 8L, 1055L, 9L); - if (expectCached) { - assertTrafficStatsValues(TEST_IFACE, myUid, 64L, 3L, 1024L, 8L); - } else { - assertTrafficStatsValues(TEST_IFACE, myUid, 65L, 8L, 1055L, 9L); - } - - // Verify the values are updated after cache expiry. - incrementCurrentTime(DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS); - assertTrafficStatsValues(TEST_IFACE, myUid, 65L, 8L, 1055L, 9L); - } - - private void mockTrafficStatsValues(long rxBytes, long rxPackets, - long txBytes, long txPackets) { - // In practice, keys and operations are not used and filled with default values when - // returned by JNI layer. - final NetworkStats.Entry entry = new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, - rxBytes, rxPackets, txBytes, txPackets, 0L); - mDeps.setNativeStat(entry); - } - - // Assert for 3 different API return values respectively. - private void assertTrafficStatsValues(String iface, int uid, long rxBytes, long rxPackets, - long txBytes, long txPackets) { - assertStatsResultEquals(mService.getTotalStats(), rxBytes, rxPackets, txBytes, txPackets); - assertStatsResultEquals(mService.getIfaceStats(iface), rxBytes, rxPackets, txBytes, - txPackets); - assertStatsResultEquals(mService.getUidStats(uid), rxBytes, rxPackets, txBytes, txPackets); - } - - private void assertStatsResultEquals(StatsResult stats, long rxBytes, long rxPackets, - long txBytes, long txPackets) { - assertEquals(rxBytes, stats.rxBytes); - assertEquals(rxPackets, stats.rxPackets); - assertEquals(txBytes, stats.txBytes); - assertEquals(txPackets, stats.txPackets); - } - private void assertShouldRunComparison(boolean expected, boolean isDebuggable) { assertEquals("shouldRunComparison (debuggable=" + isDebuggable + "): ", expected, mService.shouldRunComparison()); diff --git a/tests/unit/java/com/android/server/net/TrafficStatsRateLimitCacheTest.kt b/tests/unit/java/com/android/server/net/TrafficStatsRateLimitCacheTest.kt deleted file mode 100644 index 99f762d0c2..0000000000 --- a/tests/unit/java/com/android/server/net/TrafficStatsRateLimitCacheTest.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net - -import android.net.NetworkStats.Entry -import com.android.testutils.DevSdkIgnoreRunner -import java.time.Clock -import java.util.function.Supplier -import kotlin.test.assertEquals -import kotlin.test.assertNull -import kotlin.test.fail -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.doReturn -import org.mockito.Mockito.mock -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` - -@RunWith(DevSdkIgnoreRunner::class) -class TrafficStatsRateLimitCacheTest { - companion object { - private const val expiryDurationMs = 1000L - private const val maxSize = 2 - } - - private val clock = mock(Clock::class.java) - private val entry = mock(Entry::class.java) - private val cache = TrafficStatsRateLimitCache(clock, expiryDurationMs, maxSize) - - @Test - fun testGet_returnsEntryIfNotExpired() { - cache.put("iface", 2, entry) - doReturn(500L).`when`(clock).millis() // Set clock to before expiry - val result = cache.get("iface", 2) - assertEquals(entry, result) - } - - @Test - fun testGet_returnsNullIfExpired() { - cache.put("iface", 2, entry) - doReturn(2000L).`when`(clock).millis() // Set clock to after expiry - assertNull(cache.get("iface", 2)) - } - - @Test - fun testGet_returnsNullForNonExistentKey() { - val result = cache.get("otherIface", 99) - assertNull(result) - } - - @Test - fun testPutAndGet_retrievesCorrectEntryForDifferentKeys() { - val entry1 = mock(Entry::class.java) - val entry2 = mock(Entry::class.java) - - cache.put("iface1", 2, entry1) - cache.put("iface2", 4, entry2) - - assertEquals(entry1, cache.get("iface1", 2)) - assertEquals(entry2, cache.get("iface2", 4)) - } - - @Test - fun testPut_overridesExistingEntry() { - val entry1 = mock(Entry::class.java) - val entry2 = mock(Entry::class.java) - - cache.put("iface", 2, entry1) - cache.put("iface", 2, entry2) // Put with the same key - - assertEquals(entry2, cache.get("iface", 2)) - } - - @Test - fun testPut_removeLru() { - // Assumes max size is 2. Verify eldest entry get removed. - val entry1 = mock(Entry::class.java) - val entry2 = mock(Entry::class.java) - val entry3 = mock(Entry::class.java) - - cache.put("iface1", 2, entry1) - cache.put("iface2", 4, entry2) - cache.put("iface3", 8, entry3) - - assertNull(cache.get("iface1", 2)) - assertEquals(entry2, cache.get("iface2", 4)) - assertEquals(entry3, cache.get("iface3", 8)) - } - - @Test - fun testGetOrCompute_cacheHit() { - val entry1 = mock(Entry::class.java) - - cache.put("iface1", 2, entry1) - - // Set clock to before expiry. - doReturn(500L).`when`(clock).millis() - - // Now call getOrCompute - val result = cache.getOrCompute("iface1", 2) { - fail("Supplier should not be called") - } - - // Assertions - assertEquals(entry1, result) // Should get the cached entry. - } - - @Suppress("UNCHECKED_CAST") - @Test - fun testGetOrCompute_cacheMiss() { - val entry1 = mock(Entry::class.java) - - cache.put("iface1", 2, entry1) - - // Set clock to after expiry. - doReturn(1500L).`when`(clock).millis() - - // Mock the supplier to return our network stats entry. - val supplier = mock(Supplier::class.java) as Supplier - doReturn(entry1).`when`(supplier).get() - - // Now call getOrCompute. - val result = cache.getOrCompute("iface1", 2, supplier) - - // Assertions. - assertEquals(entry1, result) // Should get the cached entry. - verify(supplier).get() - } - - @Test - fun testClear() { - cache.put("iface", 2, entry) - cache.clear() - assertNull(cache.get("iface", 2)) - } -}