Merge "Remove service-side TrafficStats rate limit cache" into main
This commit is contained in:
commit
fe61faa220
6 changed files with 9 additions and 525 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -892,11 +892,6 @@ public class TrafficStats {
|
|||
if (uidCache != null) {
|
||||
uidCache.clear();
|
||||
}
|
||||
try {
|
||||
getStatsService().clearTrafficStatsRateLimitCaches();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<TrafficStatsRateLimitCache.TrafficStatsCacheKey, NetworkStats.Entry> {
|
||||
|
||||
/**
|
||||
* 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<NetworkStats.Entry> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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<Entry>
|
||||
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))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue