Merge changes from topic "bandwidth-limiting"

* changes:
  Add bandwidth limiting to CS
  Add setting that controls network rate limit
This commit is contained in:
Patrick Rohr
2022-02-09 18:00:04 +00:00
committed by Gerrit Code Review
5 changed files with 373 additions and 1 deletions

View File

@@ -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));
}
}