Merge changes from topic "bandwidth-limiting"
* changes: Add bandwidth limiting to CS Add setting that controls network rate limit
This commit is contained in:
@@ -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.");
|
||||
|
||||
Reference in New Issue
Block a user