Merge changes from topic "bandwidth-limiting"
* changes: Add bandwidth limiting to CS Add setting that controls network rate limit
This commit is contained in:
@@ -69,6 +69,7 @@ package android.net {
|
||||
method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
|
||||
method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
|
||||
method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
|
||||
method public static long getIngressRateLimitInBytesPerSecond(@NonNull android.content.Context);
|
||||
method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
|
||||
method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
|
||||
method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context);
|
||||
@@ -89,6 +90,7 @@ package android.net {
|
||||
method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
|
||||
method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
|
||||
method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
|
||||
method public static void setIngressRateLimitInBytesPerSecond(@NonNull android.content.Context, @IntRange(from=0xffffffff, to=java.lang.Integer.MAX_VALUE) long);
|
||||
method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
|
||||
method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
|
||||
method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
|
||||
|
||||
@@ -383,6 +383,14 @@ public class ConnectivitySettingsManager {
|
||||
public static final String UIDS_ALLOWED_ON_RESTRICTED_NETWORKS =
|
||||
"uids_allowed_on_restricted_networks";
|
||||
|
||||
/**
|
||||
* A global rate limit that applies to all networks with NET_CAPABILITY_INTERNET when enabled.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String INGRESS_RATE_LIMIT_BYTES_PER_SECOND =
|
||||
"ingress_rate_limit_bytes_per_second";
|
||||
|
||||
/**
|
||||
* Get mobile data activity timeout from {@link Settings}.
|
||||
*
|
||||
@@ -1071,4 +1079,37 @@ public class ConnectivitySettingsManager {
|
||||
Settings.Global.putString(context.getContentResolver(), UIDS_ALLOWED_ON_RESTRICTED_NETWORKS,
|
||||
uids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global network bandwidth rate limit.
|
||||
*
|
||||
* The limit is only applicable to networks that provide internet connectivity. If the setting
|
||||
* is unset, it defaults to -1.
|
||||
*
|
||||
* @param context The {@link Context} to query the setting.
|
||||
* @return The rate limit in number of bytes per second or -1 if disabled.
|
||||
*/
|
||||
public static long getIngressRateLimitInBytesPerSecond(@NonNull Context context) {
|
||||
return Settings.Global.getLong(context.getContentResolver(),
|
||||
INGRESS_RATE_LIMIT_BYTES_PER_SECOND, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the global network bandwidth rate limit.
|
||||
*
|
||||
* The limit is only applicable to networks that provide internet connectivity.
|
||||
*
|
||||
* @param context The {@link Context} to set the setting.
|
||||
* @param rateLimitInBytesPerSec The rate limit in number of bytes per second or -1 to disable.
|
||||
*/
|
||||
public static void setIngressRateLimitInBytesPerSecond(@NonNull Context context,
|
||||
@IntRange(from = -1, to = Integer.MAX_VALUE) long rateLimitInBytesPerSec) {
|
||||
if (rateLimitInBytesPerSec < -1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Rate limit must be within the range [-1, Integer.MAX_VALUE]");
|
||||
}
|
||||
Settings.Global.putLong(context.getContentResolver(),
|
||||
INGRESS_RATE_LIMIT_BYTES_PER_SECOND,
|
||||
rateLimitInBytesPerSec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequi
|
||||
import static android.os.Process.INVALID_UID;
|
||||
import static android.os.Process.VPN_UID;
|
||||
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
|
||||
import static android.system.OsConstants.ETH_P_ALL;
|
||||
import static android.system.OsConstants.IPPROTO_TCP;
|
||||
import static android.system.OsConstants.IPPROTO_UDP;
|
||||
|
||||
@@ -197,6 +198,7 @@ import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener;
|
||||
import android.net.resolv.aidl.Nat64PrefixEventParcel;
|
||||
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
|
||||
import android.net.shared.PrivateDnsConfig;
|
||||
import android.net.util.InterfaceParams;
|
||||
import android.net.util.MultinetworkPolicyTracker;
|
||||
import android.os.BatteryStatsManager;
|
||||
import android.os.Binder;
|
||||
@@ -248,6 +250,7 @@ import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
|
||||
import com.android.net.module.util.LocationPermissionChecker;
|
||||
import com.android.net.module.util.NetworkCapabilitiesUtils;
|
||||
import com.android.net.module.util.PermissionUtils;
|
||||
import com.android.net.module.util.TcUtils;
|
||||
import com.android.net.module.util.netlink.InetDiagMessage;
|
||||
import com.android.server.connectivity.AutodestructReference;
|
||||
import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
|
||||
@@ -274,6 +277,7 @@ import com.android.server.connectivity.UidRangeUtils;
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.Inet4Address;
|
||||
@@ -708,6 +712,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
*/
|
||||
private static final int EVENT_SET_TEST_ALLOW_BAD_WIFI_UNTIL = 55;
|
||||
|
||||
/**
|
||||
* Used internally when INGRESS_RATE_LIMIT_BYTES_PER_SECOND setting changes.
|
||||
*/
|
||||
private static final int EVENT_INGRESS_RATE_LIMIT_CHANGED = 56;
|
||||
|
||||
/**
|
||||
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
|
||||
* should be shown.
|
||||
@@ -725,6 +734,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
*/
|
||||
private static final long MAX_TEST_ALLOW_BAD_WIFI_UNTIL_MS = 5 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* The priority of the tc police rate limiter -- smaller value is higher priority.
|
||||
* This value needs to be coordinated with PRIO_CLAT, PRIO_TETHER4, and PRIO_TETHER6.
|
||||
*/
|
||||
private static final short TC_PRIO_POLICE = 1;
|
||||
|
||||
/**
|
||||
* The BPF program attached to the tc-police hook to account for to-be-dropped traffic.
|
||||
*/
|
||||
private static final String TC_POLICE_BPF_PROG_PATH =
|
||||
"/sys/fs/bpf/prog_netd_schedact_ingress_account";
|
||||
|
||||
private static String eventName(int what) {
|
||||
return sMagicDecoderRing.get(what, Integer.toString(what));
|
||||
}
|
||||
@@ -815,6 +836,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
final Map<IBinder, ConnectivityDiagnosticsCallbackInfo> mConnectivityDiagnosticsCallbacks =
|
||||
new HashMap<>();
|
||||
|
||||
// Rate limit applicable to all internet capable networks (-1 = disabled). This value is
|
||||
// configured via {@link
|
||||
// ConnectivitySettingsManager#INGRESS_RATE_LIMIT_BYTES_PER_SECOND}
|
||||
// Only the handler thread is allowed to access this field.
|
||||
private long mIngressRateLimit = -1;
|
||||
|
||||
/**
|
||||
* Implements support for the legacy "one network per network type" model.
|
||||
*
|
||||
@@ -1367,6 +1394,48 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
public BpfNetMaps getBpfNetMaps(INetd netd) {
|
||||
return new BpfNetMaps(netd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link TcUtils#tcFilterAddDevIngressPolice}
|
||||
*/
|
||||
public void enableIngressRateLimit(String iface, long rateInBytesPerSecond) {
|
||||
final InterfaceParams params = InterfaceParams.getByName(iface);
|
||||
if (params == null) {
|
||||
// the interface might have disappeared.
|
||||
logw("Failed to get interface params for interface " + iface);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// converting rateInBytesPerSecond from long to int is safe here because the
|
||||
// setting's range is limited to INT_MAX.
|
||||
// TODO: add long/uint64 support to tcFilterAddDevIngressPolice.
|
||||
TcUtils.tcFilterAddDevIngressPolice(params.index, TC_PRIO_POLICE, (short) ETH_P_ALL,
|
||||
(int) rateInBytesPerSecond, TC_POLICE_BPF_PROG_PATH);
|
||||
} catch (IOException e) {
|
||||
loge("TcUtils.tcFilterAddDevIngressPolice(ifaceIndex=" + params.index
|
||||
+ ", PRIO_POLICE, ETH_P_ALL, rateInBytesPerSecond="
|
||||
+ rateInBytesPerSecond + ", bpfProgPath=" + TC_POLICE_BPF_PROG_PATH
|
||||
+ ") failure: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps {@link TcUtils#tcFilterDelDev}
|
||||
*/
|
||||
public void disableIngressRateLimit(String iface) {
|
||||
final InterfaceParams params = InterfaceParams.getByName(iface);
|
||||
if (params == null) {
|
||||
// the interface might have disappeared.
|
||||
logw("Failed to get interface params for interface " + iface);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
TcUtils.tcFilterDelDev(params.index, true, TC_PRIO_POLICE, (short) ETH_P_ALL);
|
||||
} catch (IOException e) {
|
||||
loge("TcUtils.tcFilterDelDev(ifaceIndex=" + params.index
|
||||
+ ", ingress=true, PRIO_POLICE, ETH_P_ALL) failure: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectivityService(Context context) {
|
||||
@@ -1541,6 +1610,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
} catch (ErrnoException e) {
|
||||
loge("Unable to create DscpPolicyTracker");
|
||||
}
|
||||
|
||||
mIngressRateLimit = ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond(
|
||||
mContext);
|
||||
}
|
||||
|
||||
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
|
||||
@@ -1611,6 +1683,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
mHandler.sendEmptyMessage(EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateIngressRateLimit() {
|
||||
mHandler.sendEmptyMessage(EVENT_INGRESS_RATE_LIMIT_CHANGED);
|
||||
}
|
||||
|
||||
private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, int id) {
|
||||
final boolean enable = mContext.getResources().getBoolean(id);
|
||||
handleAlwaysOnNetworkRequest(networkRequest, enable);
|
||||
@@ -1672,6 +1749,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
mSettingsObserver.observe(
|
||||
Settings.Secure.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_PREFERRED_UIDS),
|
||||
EVENT_MOBILE_DATA_PREFERRED_UIDS_CHANGED);
|
||||
|
||||
// Watch for ingress rate limit changes.
|
||||
mSettingsObserver.observe(
|
||||
Settings.Secure.getUriFor(
|
||||
ConnectivitySettingsManager.INGRESS_RATE_LIMIT_BYTES_PER_SECOND),
|
||||
EVENT_INGRESS_RATE_LIMIT_CHANGED);
|
||||
}
|
||||
|
||||
private void registerPrivateDnsSettingsCallbacks() {
|
||||
@@ -4091,6 +4174,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
// for an unnecessarily long time.
|
||||
destroyNativeNetwork(nai);
|
||||
mDnsManager.removeNetwork(nai.network);
|
||||
|
||||
// clean up tc police filters on interface.
|
||||
if (canNetworkBeRateLimited(nai) && mIngressRateLimit >= 0) {
|
||||
mDeps.disableIngressRateLimit(nai.linkProperties.getInterfaceName());
|
||||
}
|
||||
}
|
||||
mNetIdManager.releaseNetId(nai.network.getNetId());
|
||||
nai.onNetworkDestroyed();
|
||||
@@ -5158,6 +5246,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
final long timeMs = ((Long) msg.obj).longValue();
|
||||
mMultinetworkPolicyTracker.setTestAllowBadWifiUntil(timeMs);
|
||||
break;
|
||||
case EVENT_INGRESS_RATE_LIMIT_CHANGED:
|
||||
handleIngressRateLimitChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8854,6 +8945,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
// A network that has just connected has zero requests and is thus a foreground network.
|
||||
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
|
||||
|
||||
// If a rate limit has been configured and is applicable to this network (network
|
||||
// provides internet connectivity), apply it.
|
||||
// Note: in case of a system server crash, there is a very small chance that this
|
||||
// leaves some interfaces rate limited (i.e. if the rate limit had been changed just
|
||||
// before the crash and was never applied). One solution would be to delete all
|
||||
// potential tc police filters every time this is called. Since this is an unlikely
|
||||
// scenario in the first place (and worst case, the interface stays rate limited until
|
||||
// the device is rebooted), this seems a little overkill.
|
||||
if (canNetworkBeRateLimited(networkAgent) && mIngressRateLimit >= 0) {
|
||||
mDeps.enableIngressRateLimit(networkAgent.linkProperties.getInterfaceName(),
|
||||
mIngressRateLimit);
|
||||
}
|
||||
|
||||
if (!createNativeNetwork(networkAgent)) return;
|
||||
if (networkAgent.propagateUnderlyingCapabilities()) {
|
||||
// Initialize the network's capabilities to their starting values according to the
|
||||
@@ -10514,6 +10618,39 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
rematchAllNetworksAndRequests();
|
||||
}
|
||||
|
||||
private void handleIngressRateLimitChanged() {
|
||||
final long oldIngressRateLimit = mIngressRateLimit;
|
||||
mIngressRateLimit = ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond(
|
||||
mContext);
|
||||
for (final NetworkAgentInfo networkAgent : mNetworkAgentInfos) {
|
||||
if (canNetworkBeRateLimited(networkAgent)) {
|
||||
// If rate limit has previously been enabled, remove the old limit first.
|
||||
if (oldIngressRateLimit >= 0) {
|
||||
mDeps.disableIngressRateLimit(networkAgent.linkProperties.getInterfaceName());
|
||||
}
|
||||
if (mIngressRateLimit >= 0) {
|
||||
mDeps.enableIngressRateLimit(networkAgent.linkProperties.getInterfaceName(),
|
||||
mIngressRateLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canNetworkBeRateLimited(@NonNull final NetworkAgentInfo networkAgent) {
|
||||
if (!networkAgent.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) {
|
||||
// rate limits only apply to networks that provide internet connectivity.
|
||||
return false;
|
||||
}
|
||||
|
||||
final String iface = networkAgent.linkProperties.getInterfaceName();
|
||||
if (iface == null) {
|
||||
// This can never happen.
|
||||
logwtf("canNetworkBeRateLimited: LinkProperties#getInterfaceName returns null");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void enforceAutomotiveDevice() {
|
||||
PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE,
|
||||
"setOemNetworkPreference() is only available on automotive devices.");
|
||||
|
||||
@@ -39,6 +39,7 @@ import android.net.ConnectivitySettingsManager.getConnectivityKeepPendingIntentD
|
||||
import android.net.ConnectivitySettingsManager.getDnsResolverSampleRanges
|
||||
import android.net.ConnectivitySettingsManager.getDnsResolverSampleValidityDuration
|
||||
import android.net.ConnectivitySettingsManager.getDnsResolverSuccessThresholdPercent
|
||||
import android.net.ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond
|
||||
import android.net.ConnectivitySettingsManager.getMobileDataActivityTimeout
|
||||
import android.net.ConnectivitySettingsManager.getMobileDataAlwaysOn
|
||||
import android.net.ConnectivitySettingsManager.getNetworkSwitchNotificationMaximumDailyCount
|
||||
@@ -51,6 +52,7 @@ import android.net.ConnectivitySettingsManager.setConnectivityKeepPendingIntentD
|
||||
import android.net.ConnectivitySettingsManager.setDnsResolverSampleRanges
|
||||
import android.net.ConnectivitySettingsManager.setDnsResolverSampleValidityDuration
|
||||
import android.net.ConnectivitySettingsManager.setDnsResolverSuccessThresholdPercent
|
||||
import android.net.ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond
|
||||
import android.net.ConnectivitySettingsManager.setMobileDataActivityTimeout
|
||||
import android.net.ConnectivitySettingsManager.setMobileDataAlwaysOn
|
||||
import android.net.ConnectivitySettingsManager.setNetworkSwitchNotificationMaximumDailyCount
|
||||
@@ -292,4 +294,19 @@ class ConnectivitySettingsManagerTest {
|
||||
setter = { setWifiAlwaysRequested(context, it) },
|
||||
testIntValues = intArrayOf(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInternetNetworkRateLimitInBytesPerSecond() {
|
||||
val defaultRate = getIngressRateLimitInBytesPerSecond(context)
|
||||
val testRate = 1000L
|
||||
setIngressRateLimitInBytesPerSecond(context, testRate)
|
||||
assertEquals(testRate, getIngressRateLimitInBytesPerSecond(context))
|
||||
|
||||
setIngressRateLimitInBytesPerSecond(context, defaultRate)
|
||||
assertEquals(defaultRate, getIngressRateLimitInBytesPerSecond(context))
|
||||
|
||||
assertFailsWith<IllegalArgumentException>("Expected failure, but setting accepted") {
|
||||
setIngressRateLimitInBytesPerSecond(context, -10)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,6 @@ import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@@ -388,6 +387,7 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -1963,6 +1963,25 @@ public class ConnectivityServiceTest {
|
||||
public BpfNetMaps getBpfNetMaps(INetd netd) {
|
||||
return mBpfNetMaps;
|
||||
}
|
||||
|
||||
final ArrayTrackRecord<Pair<String, Long>> mRateLimitHistory = new ArrayTrackRecord<>();
|
||||
final Map<String, Long> mActiveRateLimit = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void enableIngressRateLimit(final String iface, final long rateInBytesPerSecond) {
|
||||
mRateLimitHistory.add(new Pair<>(iface, rateInBytesPerSecond));
|
||||
// Due to a TC limitation, the rate limit needs to be removed before it can be
|
||||
// updated. Check that this happened.
|
||||
assertEquals(-1L, (long) mActiveRateLimit.getOrDefault(iface, -1L));
|
||||
mActiveRateLimit.put(iface, rateInBytesPerSecond);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableIngressRateLimit(final String iface) {
|
||||
mRateLimitHistory.add(new Pair<>(iface, -1L));
|
||||
assertNotEquals(-1L, (long) mActiveRateLimit.getOrDefault(iface, -1L));
|
||||
mActiveRateLimit.put(iface, -1L);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
|
||||
@@ -5027,6 +5046,13 @@ public class ConnectivityServiceTest {
|
||||
waitForIdle();
|
||||
}
|
||||
|
||||
private void setIngressRateLimit(int rateLimitInBytesPerSec) {
|
||||
ConnectivitySettingsManager.setIngressRateLimitInBytesPerSecond(mServiceContext,
|
||||
rateLimitInBytesPerSec);
|
||||
mService.updateIngressRateLimit();
|
||||
waitForIdle();
|
||||
}
|
||||
|
||||
private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
|
||||
NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
|
||||
assertNotNull(nc);
|
||||
@@ -15339,4 +15365,153 @@ public class ConnectivityServiceTest {
|
||||
ConnectivityManager.TYPE_NONE, null /* hostAddress */, "com.not.package.owner",
|
||||
null /* callingAttributionTag */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateRateLimit_EnableDisable() throws Exception {
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
|
||||
final LinkProperties cellLp = new LinkProperties();
|
||||
cellLp.setInterfaceName(MOBILE_IFNAME);
|
||||
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
|
||||
mCellNetworkAgent.connect(false);
|
||||
|
||||
waitForIdle();
|
||||
|
||||
final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadWifi =
|
||||
mDeps.mRateLimitHistory.newReadHead();
|
||||
final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadCell =
|
||||
mDeps.mRateLimitHistory.newReadHead();
|
||||
|
||||
// set rate limit to 8MBit/s => 1MB/s
|
||||
final int rateLimitInBytesPerSec = 1 * 1000 * 1000;
|
||||
setIngressRateLimit(rateLimitInBytesPerSec);
|
||||
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName()
|
||||
&& it.second == rateLimitInBytesPerSec));
|
||||
assertNotNull(readHeadCell.poll(TIMEOUT_MS,
|
||||
it -> it.first == cellLp.getInterfaceName()
|
||||
&& it.second == rateLimitInBytesPerSec));
|
||||
|
||||
// disable rate limiting
|
||||
setIngressRateLimit(-1);
|
||||
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName() && it.second == -1));
|
||||
assertNotNull(readHeadCell.poll(TIMEOUT_MS,
|
||||
it -> it.first == cellLp.getInterfaceName() && it.second == -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateRateLimit_WhenNewNetworkIsAdded() throws Exception {
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
|
||||
waitForIdle();
|
||||
|
||||
final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHead =
|
||||
mDeps.mRateLimitHistory.newReadHead();
|
||||
|
||||
// set rate limit to 8MBit/s => 1MB/s
|
||||
final int rateLimitInBytesPerSec = 1 * 1000 * 1000;
|
||||
setIngressRateLimit(rateLimitInBytesPerSec);
|
||||
assertNotNull(readHead.poll(TIMEOUT_MS, it -> it.first == wifiLp.getInterfaceName()
|
||||
&& it.second == rateLimitInBytesPerSec));
|
||||
|
||||
final LinkProperties cellLp = new LinkProperties();
|
||||
cellLp.setInterfaceName(MOBILE_IFNAME);
|
||||
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
|
||||
mCellNetworkAgent.connect(false);
|
||||
assertNotNull(readHead.poll(TIMEOUT_MS, it -> it.first == cellLp.getInterfaceName()
|
||||
&& it.second == rateLimitInBytesPerSec));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateRateLimit_OnlyAffectsInternetCapableNetworks() throws Exception {
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
|
||||
mWiFiNetworkAgent.connectWithoutInternet();
|
||||
|
||||
waitForIdle();
|
||||
|
||||
setIngressRateLimit(1000);
|
||||
setIngressRateLimit(-1);
|
||||
|
||||
final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadWifi =
|
||||
mDeps.mRateLimitHistory.newReadHead();
|
||||
assertNull(readHeadWifi.poll(TIMEOUT_MS, it -> it.first == wifiLp.getInterfaceName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateRateLimit_DisconnectingResetsRateLimit()
|
||||
throws Exception {
|
||||
// Steps:
|
||||
// - connect network
|
||||
// - set rate limit
|
||||
// - disconnect network (interface still exists)
|
||||
// - disable rate limit
|
||||
// - connect network
|
||||
// - ensure network interface is not rate limited
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
waitForIdle();
|
||||
|
||||
final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadWifi =
|
||||
mDeps.mRateLimitHistory.newReadHead();
|
||||
|
||||
int rateLimitInBytesPerSec = 1000;
|
||||
setIngressRateLimit(rateLimitInBytesPerSec);
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName()
|
||||
&& it.second == rateLimitInBytesPerSec));
|
||||
|
||||
mWiFiNetworkAgent.disconnect();
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName() && it.second == -1));
|
||||
|
||||
setIngressRateLimit(-1);
|
||||
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
assertNull(readHeadWifi.poll(TIMEOUT_MS, it -> it.first == wifiLp.getInterfaceName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateRateLimit_UpdateExistingRateLimit() throws Exception {
|
||||
final LinkProperties wifiLp = new LinkProperties();
|
||||
wifiLp.setInterfaceName(WIFI_IFNAME);
|
||||
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
|
||||
mWiFiNetworkAgent.connect(true);
|
||||
waitForIdle();
|
||||
|
||||
final ArrayTrackRecord<Pair<String, Long>>.ReadHead readHeadWifi =
|
||||
mDeps.mRateLimitHistory.newReadHead();
|
||||
|
||||
// update an active ingress rate limit
|
||||
setIngressRateLimit(1000);
|
||||
setIngressRateLimit(2000);
|
||||
|
||||
// verify the following order of execution:
|
||||
// 1. ingress rate limit set to 1000.
|
||||
// 2. ingress rate limit disabled (triggered by updating active rate limit).
|
||||
// 3. ingress rate limit set to 2000.
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName()
|
||||
&& it.second == 1000));
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName()
|
||||
&& it.second == -1));
|
||||
assertNotNull(readHeadWifi.poll(TIMEOUT_MS,
|
||||
it -> it.first == wifiLp.getInterfaceName()
|
||||
&& it.second == 2000));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user