Merge "Add new methods to redact NetworkCapabilities & LinkProperties"
diff --git a/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt b/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt
index 88c77f2..c1d87bb 100644
--- a/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt
+++ b/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt
@@ -1,3 +1,216 @@
+Landroid/net/IIpSecService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/net/IIpSecService$Stub$Proxy;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
+Landroid/net/IIpSecService$Stub$Proxy;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
+Landroid/net/IIpSecService$Stub$Proxy;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V
+Landroid/net/IIpSecService$Stub$Proxy;->applyTunnelModeTransform(IIILjava/lang/String;)V
+Landroid/net/IIpSecService$Stub$Proxy;->closeUdpEncapsulationSocket(I)V
+Landroid/net/IIpSecService$Stub$Proxy;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse;
+Landroid/net/IIpSecService$Stub$Proxy;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse;
+Landroid/net/IIpSecService$Stub$Proxy;->deleteTransform(I)V
+Landroid/net/IIpSecService$Stub$Proxy;->deleteTunnelInterface(ILjava/lang/String;)V
+Landroid/net/IIpSecService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
+Landroid/net/IIpSecService$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/net/IIpSecService$Stub$Proxy;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse;
+Landroid/net/IIpSecService$Stub$Proxy;->releaseSecurityParameterIndex(I)V
+Landroid/net/IIpSecService$Stub$Proxy;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
+Landroid/net/IIpSecService$Stub$Proxy;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V
+Landroid/net/IIpSecService$Stub;-><init>()V
+Landroid/net/IIpSecService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IIpSecService;
+Landroid/net/IIpSecService$Stub;->DESCRIPTOR:Ljava/lang/String;
+Landroid/net/IIpSecService$Stub;->TRANSACTION_addAddressToTunnelInterface:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_allocateSecurityParameterIndex:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTransportModeTransform:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTunnelModeTransform:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_closeUdpEncapsulationSocket:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_createTransform:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_createTunnelInterface:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTransform:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTunnelInterface:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_openUdpEncapsulationSocket:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_releaseSecurityParameterIndex:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_removeAddressFromTunnelInterface:I
+Landroid/net/IIpSecService$Stub;->TRANSACTION_removeTransportModeTransforms:I
+Landroid/net/IIpSecService;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
+Landroid/net/IIpSecService;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
+Landroid/net/IIpSecService;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V
+Landroid/net/IIpSecService;->applyTunnelModeTransform(IIILjava/lang/String;)V
+Landroid/net/IIpSecService;->closeUdpEncapsulationSocket(I)V
+Landroid/net/IIpSecService;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse;
+Landroid/net/IIpSecService;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse;
+Landroid/net/IIpSecService;->deleteTransform(I)V
+Landroid/net/IIpSecService;->deleteTunnelInterface(ILjava/lang/String;)V
+Landroid/net/IIpSecService;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse;
+Landroid/net/IIpSecService;->releaseSecurityParameterIndex(I)V
+Landroid/net/IIpSecService;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
+Landroid/net/IIpSecService;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V
+Landroid/net/IpSecAlgorithm;->checkValidOrThrow(Ljava/lang/String;II)V
+Landroid/net/IpSecAlgorithm;->CRYPT_NULL:Ljava/lang/String;
+Landroid/net/IpSecAlgorithm;->equals(Landroid/net/IpSecAlgorithm;Landroid/net/IpSecAlgorithm;)Z
+Landroid/net/IpSecAlgorithm;->isAead()Z
+Landroid/net/IpSecAlgorithm;->isAuthentication()Z
+Landroid/net/IpSecAlgorithm;->isEncryption()Z
+Landroid/net/IpSecAlgorithm;->isUnsafeBuild()Z
+Landroid/net/IpSecAlgorithm;->mKey:[B
+Landroid/net/IpSecAlgorithm;->mName:Ljava/lang/String;
+Landroid/net/IpSecAlgorithm;->mTruncLenBits:I
+Landroid/net/IpSecAlgorithm;->TAG:Ljava/lang/String;
+Landroid/net/IpSecConfig;-><init>()V
+Landroid/net/IpSecConfig;-><init>(Landroid/net/IpSecConfig;)V
+Landroid/net/IpSecConfig;-><init>(Landroid/os/Parcel;)V
+Landroid/net/IpSecConfig;->CREATOR:Landroid/os/Parcelable$Creator;
+Landroid/net/IpSecConfig;->equals(Landroid/net/IpSecConfig;Landroid/net/IpSecConfig;)Z
+Landroid/net/IpSecConfig;->getAuthenticatedEncryption()Landroid/net/IpSecAlgorithm;
+Landroid/net/IpSecConfig;->getAuthentication()Landroid/net/IpSecAlgorithm;
+Landroid/net/IpSecConfig;->getDestinationAddress()Ljava/lang/String;
+Landroid/net/IpSecConfig;->getEncapRemotePort()I
+Landroid/net/IpSecConfig;->getEncapSocketResourceId()I
+Landroid/net/IpSecConfig;->getEncapType()I
+Landroid/net/IpSecConfig;->getEncryption()Landroid/net/IpSecAlgorithm;
+Landroid/net/IpSecConfig;->getMarkMask()I
+Landroid/net/IpSecConfig;->getMarkValue()I
+Landroid/net/IpSecConfig;->getMode()I
+Landroid/net/IpSecConfig;->getNattKeepaliveInterval()I
+Landroid/net/IpSecConfig;->getNetwork()Landroid/net/Network;
+Landroid/net/IpSecConfig;->getSourceAddress()Ljava/lang/String;
+Landroid/net/IpSecConfig;->getSpiResourceId()I
+Landroid/net/IpSecConfig;->mAuthenticatedEncryption:Landroid/net/IpSecAlgorithm;
+Landroid/net/IpSecConfig;->mAuthentication:Landroid/net/IpSecAlgorithm;
+Landroid/net/IpSecConfig;->mDestinationAddress:Ljava/lang/String;
+Landroid/net/IpSecConfig;->mEncapRemotePort:I
+Landroid/net/IpSecConfig;->mEncapSocketResourceId:I
+Landroid/net/IpSecConfig;->mEncapType:I
+Landroid/net/IpSecConfig;->mEncryption:Landroid/net/IpSecAlgorithm;
+Landroid/net/IpSecConfig;->mMarkMask:I
+Landroid/net/IpSecConfig;->mMarkValue:I
+Landroid/net/IpSecConfig;->mMode:I
+Landroid/net/IpSecConfig;->mNattKeepaliveInterval:I
+Landroid/net/IpSecConfig;->mNetwork:Landroid/net/Network;
+Landroid/net/IpSecConfig;->mSourceAddress:Ljava/lang/String;
+Landroid/net/IpSecConfig;->mSpiResourceId:I
+Landroid/net/IpSecConfig;->setAuthenticatedEncryption(Landroid/net/IpSecAlgorithm;)V
+Landroid/net/IpSecConfig;->setAuthentication(Landroid/net/IpSecAlgorithm;)V
+Landroid/net/IpSecConfig;->setDestinationAddress(Ljava/lang/String;)V
+Landroid/net/IpSecConfig;->setEncapRemotePort(I)V
+Landroid/net/IpSecConfig;->setEncapSocketResourceId(I)V
+Landroid/net/IpSecConfig;->setEncapType(I)V
+Landroid/net/IpSecConfig;->setEncryption(Landroid/net/IpSecAlgorithm;)V
+Landroid/net/IpSecConfig;->setMarkMask(I)V
+Landroid/net/IpSecConfig;->setMarkValue(I)V
+Landroid/net/IpSecConfig;->setMode(I)V
+Landroid/net/IpSecConfig;->setNattKeepaliveInterval(I)V
+Landroid/net/IpSecConfig;->setNetwork(Landroid/net/Network;)V
+Landroid/net/IpSecConfig;->setSourceAddress(Ljava/lang/String;)V
+Landroid/net/IpSecConfig;->setSpiResourceId(I)V
+Landroid/net/IpSecConfig;->TAG:Ljava/lang/String;
+Landroid/net/IpSecManager$IpSecTunnelInterface;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)V
+Landroid/net/IpSecManager$IpSecTunnelInterface;->addAddress(Ljava/net/InetAddress;I)V
+Landroid/net/IpSecManager$IpSecTunnelInterface;->getInterfaceName()Ljava/lang/String;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->getResourceId()I
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mCloseGuard:Ldalvik/system/CloseGuard;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mInterfaceName:Ljava/lang/String;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mLocalAddress:Ljava/net/InetAddress;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mOpPackageName:Ljava/lang/String;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mRemoteAddress:Ljava/net/InetAddress;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mResourceId:I
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mService:Landroid/net/IIpSecService;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->mUnderlyingNetwork:Landroid/net/Network;
+Landroid/net/IpSecManager$IpSecTunnelInterface;->removeAddress(Ljava/net/InetAddress;I)V
+Landroid/net/IpSecManager$ResourceUnavailableException;-><init>(Ljava/lang/String;)V
+Landroid/net/IpSecManager$SecurityParameterIndex;-><init>(Landroid/net/IIpSecService;Ljava/net/InetAddress;I)V
+Landroid/net/IpSecManager$SecurityParameterIndex;->getResourceId()I
+Landroid/net/IpSecManager$SecurityParameterIndex;->mCloseGuard:Ldalvik/system/CloseGuard;
+Landroid/net/IpSecManager$SecurityParameterIndex;->mDestinationAddress:Ljava/net/InetAddress;
+Landroid/net/IpSecManager$SecurityParameterIndex;->mResourceId:I
+Landroid/net/IpSecManager$SecurityParameterIndex;->mService:Landroid/net/IIpSecService;
+Landroid/net/IpSecManager$SecurityParameterIndex;->mSpi:I
+Landroid/net/IpSecManager$SpiUnavailableException;-><init>(Ljava/lang/String;I)V
+Landroid/net/IpSecManager$SpiUnavailableException;->mSpi:I
+Landroid/net/IpSecManager$Status;->OK:I
+Landroid/net/IpSecManager$Status;->RESOURCE_UNAVAILABLE:I
+Landroid/net/IpSecManager$Status;->SPI_UNAVAILABLE:I
+Landroid/net/IpSecManager$UdpEncapsulationSocket;-><init>(Landroid/net/IIpSecService;I)V
+Landroid/net/IpSecManager$UdpEncapsulationSocket;->getResourceId()I
+Landroid/net/IpSecManager$UdpEncapsulationSocket;->mCloseGuard:Ldalvik/system/CloseGuard;
+Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPfd:Landroid/os/ParcelFileDescriptor;
+Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPort:I
+Landroid/net/IpSecManager$UdpEncapsulationSocket;->mResourceId:I
+Landroid/net/IpSecManager$UdpEncapsulationSocket;->mService:Landroid/net/IIpSecService;
+Landroid/net/IpSecManager;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;)V
+Landroid/net/IpSecManager;->applyTunnelModeTransform(Landroid/net/IpSecManager$IpSecTunnelInterface;ILandroid/net/IpSecTransform;)V
+Landroid/net/IpSecManager;->createIpSecTunnelInterface(Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)Landroid/net/IpSecManager$IpSecTunnelInterface;
+Landroid/net/IpSecManager;->INVALID_RESOURCE_ID:I
+Landroid/net/IpSecManager;->maybeHandleServiceSpecificException(Landroid/os/ServiceSpecificException;)V
+Landroid/net/IpSecManager;->mContext:Landroid/content/Context;
+Landroid/net/IpSecManager;->mService:Landroid/net/IIpSecService;
+Landroid/net/IpSecManager;->removeTunnelModeTransform(Landroid/net/Network;Landroid/net/IpSecTransform;)V
+Landroid/net/IpSecManager;->rethrowCheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/io/IOException;
+Landroid/net/IpSecManager;->rethrowUncheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/lang/RuntimeException;
+Landroid/net/IpSecManager;->TAG:Ljava/lang/String;
+Landroid/net/IpSecSpiResponse;-><init>(I)V
+Landroid/net/IpSecSpiResponse;-><init>(III)V
+Landroid/net/IpSecSpiResponse;-><init>(Landroid/os/Parcel;)V
+Landroid/net/IpSecSpiResponse;->CREATOR:Landroid/os/Parcelable$Creator;
+Landroid/net/IpSecSpiResponse;->resourceId:I
+Landroid/net/IpSecSpiResponse;->spi:I
+Landroid/net/IpSecSpiResponse;->status:I
+Landroid/net/IpSecSpiResponse;->TAG:Ljava/lang/String;
+Landroid/net/IpSecTransform$Builder;->buildTunnelModeTransform(Ljava/net/InetAddress;Landroid/net/IpSecManager$SecurityParameterIndex;)Landroid/net/IpSecTransform;
+Landroid/net/IpSecTransform$Builder;->mConfig:Landroid/net/IpSecConfig;
+Landroid/net/IpSecTransform$Builder;->mContext:Landroid/content/Context;
+Landroid/net/IpSecTransform$NattKeepaliveCallback;-><init>()V
+Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_ERROR:I
+Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_UNSUPPORTED:I
+Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_INVALID_NETWORK:I
+Landroid/net/IpSecTransform$NattKeepaliveCallback;->onError(I)V
+Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStarted()V
+Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStopped()V
+Landroid/net/IpSecTransform;-><init>(Landroid/content/Context;Landroid/net/IpSecConfig;)V
+Landroid/net/IpSecTransform;->activate()Landroid/net/IpSecTransform;
+Landroid/net/IpSecTransform;->checkResultStatus(I)V
+Landroid/net/IpSecTransform;->ENCAP_ESPINUDP:I
+Landroid/net/IpSecTransform;->ENCAP_ESPINUDP_NON_IKE:I
+Landroid/net/IpSecTransform;->ENCAP_NONE:I
+Landroid/net/IpSecTransform;->equals(Landroid/net/IpSecTransform;Landroid/net/IpSecTransform;)Z
+Landroid/net/IpSecTransform;->getConfig()Landroid/net/IpSecConfig;
+Landroid/net/IpSecTransform;->getIpSecService()Landroid/net/IIpSecService;
+Landroid/net/IpSecTransform;->getResourceId()I
+Landroid/net/IpSecTransform;->mCallbackHandler:Landroid/os/Handler;
+Landroid/net/IpSecTransform;->mCloseGuard:Ldalvik/system/CloseGuard;
+Landroid/net/IpSecTransform;->mConfig:Landroid/net/IpSecConfig;
+Landroid/net/IpSecTransform;->mContext:Landroid/content/Context;
+Landroid/net/IpSecTransform;->mKeepalive:Landroid/net/ConnectivityManager$PacketKeepalive;
+Landroid/net/IpSecTransform;->mKeepaliveCallback:Landroid/net/ConnectivityManager$PacketKeepaliveCallback;
+Landroid/net/IpSecTransform;->MODE_TRANSPORT:I
+Landroid/net/IpSecTransform;->MODE_TUNNEL:I
+Landroid/net/IpSecTransform;->mResourceId:I
+Landroid/net/IpSecTransform;->mUserKeepaliveCallback:Landroid/net/IpSecTransform$NattKeepaliveCallback;
+Landroid/net/IpSecTransform;->startNattKeepalive(Landroid/net/IpSecTransform$NattKeepaliveCallback;ILandroid/os/Handler;)V
+Landroid/net/IpSecTransform;->stopNattKeepalive()V
+Landroid/net/IpSecTransform;->TAG:Ljava/lang/String;
+Landroid/net/IpSecTransformResponse;-><init>(I)V
+Landroid/net/IpSecTransformResponse;-><init>(II)V
+Landroid/net/IpSecTransformResponse;-><init>(Landroid/os/Parcel;)V
+Landroid/net/IpSecTransformResponse;->CREATOR:Landroid/os/Parcelable$Creator;
+Landroid/net/IpSecTransformResponse;->resourceId:I
+Landroid/net/IpSecTransformResponse;->status:I
+Landroid/net/IpSecTransformResponse;->TAG:Ljava/lang/String;
+Landroid/net/IpSecTunnelInterfaceResponse;-><init>(I)V
+Landroid/net/IpSecTunnelInterfaceResponse;-><init>(IILjava/lang/String;)V
+Landroid/net/IpSecTunnelInterfaceResponse;-><init>(Landroid/os/Parcel;)V
+Landroid/net/IpSecTunnelInterfaceResponse;->CREATOR:Landroid/os/Parcelable$Creator;
+Landroid/net/IpSecTunnelInterfaceResponse;->interfaceName:Ljava/lang/String;
+Landroid/net/IpSecTunnelInterfaceResponse;->resourceId:I
+Landroid/net/IpSecTunnelInterfaceResponse;->status:I
+Landroid/net/IpSecTunnelInterfaceResponse;->TAG:Ljava/lang/String;
+Landroid/net/IpSecUdpEncapResponse;-><init>(I)V
+Landroid/net/IpSecUdpEncapResponse;-><init>(IIILjava/io/FileDescriptor;)V
+Landroid/net/IpSecUdpEncapResponse;-><init>(Landroid/os/Parcel;)V
+Landroid/net/IpSecUdpEncapResponse;->CREATOR:Landroid/os/Parcelable$Creator;
+Landroid/net/IpSecUdpEncapResponse;->fileDescriptor:Landroid/os/ParcelFileDescriptor;
+Landroid/net/IpSecUdpEncapResponse;->port:I
+Landroid/net/IpSecUdpEncapResponse;->resourceId:I
+Landroid/net/IpSecUdpEncapResponse;->status:I
+Landroid/net/IpSecUdpEncapResponse;->TAG:Ljava/lang/String;
 Landroid/net/nsd/DnsSdTxtRecord;-><init>()V
 Landroid/net/nsd/DnsSdTxtRecord;-><init>(Landroid/net/nsd/DnsSdTxtRecord;)V
 Landroid/net/nsd/DnsSdTxtRecord;-><init>([B)V
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index 51c200b..9ca3f14 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -26,6 +26,9 @@
         // Using for test only
         "//cts/tests/netlegacy22.api",
         "//external/sl4a:__subpackages__",
+        "//frameworks/base/core/tests/bandwidthtests",
+        "//frameworks/base/core/tests/benchmarks",
+        "//frameworks/base/core/tests/utillib",
         "//frameworks/base/packages/Connectivity/tests:__subpackages__",
         "//frameworks/base/tests/vcn",
         "//frameworks/libs/net/common/testutils",
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index aa9b14e..50a3eb2 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -62,6 +62,15 @@
         // non-jarjard names of widely-used packages such as com.android.net.module.util.
         "framework-connectivity-pre-jarjar",
     ],
+    aidl: {
+        generate_get_transaction_name: true,
+        include_dirs: [
+            // For connectivity-framework classes such as Network.aidl,
+            // and connectivity-framework-t classes such as
+            // NetworkStateSnapshot.aidl
+            "packages/modules/Connectivity/framework/aidl-export",
+        ],
+    },
     apex_available: [
         "com.android.tethering",
     ],
@@ -109,6 +118,9 @@
         "//cts/tests/netlegacy22.api",
         "//cts/tests/tests/app.usage", // NetworkUsageStatsTest
         "//external/sl4a:__subpackages__",
+        "//frameworks/base/core/tests/bandwidthtests",
+        "//frameworks/base/core/tests/benchmarks",
+        "//frameworks/base/core/tests/utillib",
         "//frameworks/base/tests/vcn",
         "//frameworks/libs/net/common/testutils",
         "//frameworks/libs/net/common/tests:__subpackages__",
@@ -116,7 +128,7 @@
         "//packages/modules/CaptivePortalLogin/tests",
         "//packages/modules/Connectivity/Tethering/tests:__subpackages__",
         "//packages/modules/Connectivity/tests:__subpackages__",
-	"//packages/modules/IPsec/tests/iketests",
+        "//packages/modules/IPsec/tests/iketests",
         "//packages/modules/NetworkStack/tests:__subpackages__",
         "//packages/modules/Nearby/tests:__subpackages__",
         "//packages/modules/Wifi/service/tests/wifitests",
diff --git a/framework-t/api/OWNERS b/framework-t/api/OWNERS
new file mode 100644
index 0000000..de0f905
--- /dev/null
+++ b/framework-t/api/OWNERS
@@ -0,0 +1 @@
+file:platform/packages/modules/Connectivity:master:/nearby/OWNERS
diff --git a/framework-t/api/current.txt b/framework-t/api/current.txt
index 7977cc5..1389ff2 100644
--- a/framework-t/api/current.txt
+++ b/framework-t/api/current.txt
@@ -1,4 +1,77 @@
 // Signature format: 2.0
+package android.net {
+
+  public final class IpSecAlgorithm implements android.os.Parcelable {
+    ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
+    ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
+    method public int describeContents();
+    method @NonNull public byte[] getKey();
+    method @NonNull public String getName();
+    method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms();
+    method public int getTruncationLengthBits();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final String AUTH_AES_CMAC = "cmac(aes)";
+    field public static final String AUTH_AES_XCBC = "xcbc(aes)";
+    field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
+    field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
+    field public static final String AUTH_HMAC_MD5 = "hmac(md5)";
+    field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
+    field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
+    field public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
+    field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+    field public static final String CRYPT_AES_CBC = "cbc(aes)";
+    field public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))";
+  }
+
+  public class IpSecManager {
+    method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
+    method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+    method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
+    method public void removeTransportModeTransforms(@NonNull java.net.DatagramSocket) throws java.io.IOException;
+    method public void removeTransportModeTransforms(@NonNull java.io.FileDescriptor) throws java.io.IOException;
+    field public static final int DIRECTION_IN = 0; // 0x0
+    field public static final int DIRECTION_OUT = 1; // 0x1
+  }
+
+  public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+  }
+
+  public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+    method public void close();
+    method public int getSpi();
+  }
+
+  public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+    method public int getSpi();
+  }
+
+  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+    method public void close() throws java.io.IOException;
+    method public java.io.FileDescriptor getFileDescriptor();
+    method public int getPort();
+  }
+
+  public final class IpSecTransform implements java.lang.AutoCloseable {
+    method public void close();
+  }
+
+  public static class IpSecTransform.Builder {
+    ctor public IpSecTransform.Builder(@NonNull android.content.Context);
+    method @NonNull public android.net.IpSecTransform buildTransportModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+    method @NonNull public android.net.IpSecTransform.Builder setAuthenticatedEncryption(@NonNull android.net.IpSecAlgorithm);
+    method @NonNull public android.net.IpSecTransform.Builder setAuthentication(@NonNull android.net.IpSecAlgorithm);
+    method @NonNull public android.net.IpSecTransform.Builder setEncryption(@NonNull android.net.IpSecAlgorithm);
+    method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int);
+  }
+
+}
+
 package android.net.nsd {
 
   public final class NsdManager {
diff --git a/framework-t/api/lint-baseline.txt b/framework-t/api/lint-baseline.txt
new file mode 100644
index 0000000..1e30747
--- /dev/null
+++ b/framework-t/api/lint-baseline.txt
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+GenericException: android.net.IpSecManager.SecurityParameterIndex#finalize():
+    Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.IpSecManager.UdpEncapsulationSocket#finalize():
+    Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.net.IpSecTransform#finalize():
+    Methods must not throw generic exceptions (`java.lang.Throwable`)
diff --git a/framework-t/api/module-lib-current.txt b/framework-t/api/module-lib-current.txt
index 81d89c6..2ff3451 100644
--- a/framework-t/api/module-lib-current.txt
+++ b/framework-t/api/module-lib-current.txt
@@ -5,5 +5,13 @@
     method public static void registerServiceWrappers();
   }
 
+  public class IpSecManager {
+    field public static final int DIRECTION_FWD = 2; // 0x2
+  }
+
+  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+    method public int getResourceId();
+  }
+
 }
 
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index d802177..041bcaf 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -1 +1,22 @@
 // Signature format: 2.0
+package android.net {
+
+  public class IpSecManager {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+  }
+
+  public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+    method public void close();
+    method @NonNull public String getInterfaceName();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException;
+  }
+
+  public static class IpSecTransform.Builder {
+    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+  }
+
+}
+
diff --git a/framework-t/api/system-lint-baseline.txt b/framework-t/api/system-lint-baseline.txt
new file mode 100644
index 0000000..9baf991
--- /dev/null
+++ b/framework-t/api/system-lint-baseline.txt
@@ -0,0 +1,7 @@
+// Baseline format: 1.0
+BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
+    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex)
+
+
+GenericException: android.net.IpSecManager.IpSecTunnelInterface#finalize():
+    Methods must not throw generic exceptions (`java.lang.Throwable`)
diff --git a/framework/Android.bp b/framework/Android.bp
index 921c4fb..da16a8d 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -131,6 +131,9 @@
         "//cts/tests/tests/app.usage", // NetworkUsageStatsTest
         "//external/sl4a:__subpackages__",
         "//frameworks/base/packages/Connectivity/tests:__subpackages__",
+        "//frameworks/base/core/tests/bandwidthtests",
+        "//frameworks/base/core/tests/benchmarks",
+        "//frameworks/base/core/tests/utillib",
         "//frameworks/base/tests/vcn",
         "//frameworks/libs/net/common/testutils",
         "//frameworks/libs/net/common/tests:__subpackages__",
diff --git a/framework/aidl-export/android/net/NetworkStateSnapshot.aidl b/framework/aidl-export/android/net/NetworkStateSnapshot.aidl
new file mode 100644
index 0000000..cb602d7
--- /dev/null
+++ b/framework/aidl-export/android/net/NetworkStateSnapshot.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2021, 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 android.net;
+
+parcelable NetworkStateSnapshot;
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index dec9d35..5579db6 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -71,6 +71,7 @@
     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);
@@ -91,6 +92,7 @@
     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>);
@@ -132,7 +134,7 @@
 
   public static final class NetworkAgentConfig.Builder {
     method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
-    method @NonNull public android.net.NetworkAgentConfig.Builder setExcludeLocalRoutesVpn(boolean);
+    method @NonNull public android.net.NetworkAgentConfig.Builder setLocalRoutesExcludedForVpn(boolean);
     method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
     method @NonNull public android.net.NetworkAgentConfig.Builder setVpnRequiresValidation(boolean);
   }
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 8fc0065..4e28b29 100644
--- a/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/framework/src/android/net/ConnectivitySettingsManager.java
@@ -384,6 +384,14 @@
             "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}.
      *
      * @param context The {@link Context} to query the setting.
@@ -1071,4 +1079,37 @@
         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);
+    }
 }
diff --git a/framework/src/android/net/NetworkAgentConfig.java b/framework/src/android/net/NetworkAgentConfig.java
index 3f5d5e5..1991a58 100644
--- a/framework/src/android/net/NetworkAgentConfig.java
+++ b/framework/src/android/net/NetworkAgentConfig.java
@@ -244,7 +244,7 @@
      * @return whether local traffic is excluded from the VPN network.
      * @hide
      */
-    public boolean getExcludeLocalRouteVpn() {
+    public boolean areLocalRoutesExcludedForVpn() {
         return excludeLocalRouteVpn;
     }
 
@@ -472,7 +472,7 @@
          */
         @NonNull
         @SystemApi(client = MODULE_LIBRARIES)
-        public Builder setExcludeLocalRoutesVpn(boolean excludeLocalRoutes) {
+        public Builder setLocalRoutesExcludedForVpn(boolean excludeLocalRoutes) {
             mConfig.excludeLocalRouteVpn = excludeLocalRoutes;
             return this;
         }
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index b7a6076..4f9d845 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -423,6 +423,7 @@
          *
          * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead.
          */
+        @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
         @Deprecated
         public Builder setNetworkSpecifier(String networkSpecifier) {
             try {
@@ -439,6 +440,15 @@
                 } else if (mNetworkCapabilities.hasTransport(TRANSPORT_TEST)) {
                     return setNetworkSpecifier(new TestNetworkSpecifier(networkSpecifier));
                 } else {
+                    // TODO: b/193460475 remove comment once fixed
+                    // @SuppressLint("NewApi") is due to EthernetNetworkSpecifier being changed
+                    // from @SystemApi to public. EthernetNetworkSpecifier was introduced in Android
+                    // 12 as @SystemApi(client = MODULE_LIBRARIES) and made public in Android 13.
+                    // b/193460475 means in the above situation the tools will think
+                    // EthernetNetworkSpecifier didn't exist in Android 12, causing the NewApi lint
+                    // to fail. In this case, this is actually safe because this code was
+                    // modularized in Android 12, so it can't run on SDKs before Android 12 and is
+                    // therefore guaranteed to always have this class available to it.
                     return setNetworkSpecifier(new EthernetNetworkSpecifier(networkSpecifier));
                 }
             }
diff --git a/nearby/OWNERS b/nearby/OWNERS
new file mode 100644
index 0000000..980c221
--- /dev/null
+++ b/nearby/OWNERS
@@ -0,0 +1,4 @@
+chunzhang@google.com
+weiwa@google.com
+weiwu@google.com
+xlythe@google.com
diff --git a/netd/Android.bp b/netd/Android.bp
index b98a859..5ac02d3 100644
--- a/netd/Android.bp
+++ b/netd/Android.bp
@@ -13,6 +13,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library {
     name: "libnetd_updatable",
     version_script: "libnetd_updatable.map.txt",
diff --git a/service-t/src/com/android/server/ConnectivityServiceInitializer.java b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
index 23d8bdc..67757af 100644
--- a/service-t/src/com/android/server/ConnectivityServiceInitializer.java
+++ b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
@@ -28,6 +28,7 @@
 public final class ConnectivityServiceInitializer extends SystemService {
     private static final String TAG = ConnectivityServiceInitializer.class.getSimpleName();
     private final ConnectivityService mConnectivity;
+    private final IpSecService mIpSecService;
     private final NsdService mNsdService;
 
     public ConnectivityServiceInitializer(Context context) {
@@ -35,6 +36,7 @@
         // Load JNI libraries used by ConnectivityService and its dependencies
         System.loadLibrary("service-connectivity");
         mConnectivity = new ConnectivityService(context);
+        mIpSecService = createIpSecService(context);
         mNsdService = createNsdService(context);
     }
 
@@ -43,12 +45,27 @@
         Log.i(TAG, "Registering " + Context.CONNECTIVITY_SERVICE);
         publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
                 /* allowIsolated= */ false);
+
+        if (mIpSecService != null) {
+            Log.i(TAG, "Registering " + Context.IPSEC_SERVICE);
+            publishBinderService(Context.IPSEC_SERVICE, mIpSecService, /* allowIsolated= */ false);
+        }
+
         if (mNsdService != null) {
             Log.i(TAG, "Registering " + Context.NSD_SERVICE);
             publishBinderService(Context.NSD_SERVICE, mNsdService, /* allowIsolated= */ false);
         }
     }
 
+    /**
+     * Return IpSecService instance, or null if current SDK is lower than T.
+     */
+    private IpSecService createIpSecService(final Context context) {
+        if (!SdkLevel.isAtLeastT()) return null;
+
+        return new IpSecService(context);
+    }
+
     /** Return NsdService instance or null if current SDK is lower than T */
     private NsdService createNsdService(final Context context) {
         if (!SdkLevel.isAtLeastT()) return null;
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index 2aaa4c3..c29eb2b 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -202,24 +202,6 @@
     mTc.setPermissionForUids(permission, data);
 }
 
-static jint native_setCounterSet(JNIEnv* env, jobject clazz, jint setNum, jint uid) {
-    uid_t callingUid = getuid();
-    int res = mTc.setCounterSet(setNum, (uid_t)uid, callingUid);
-    if (res) {
-      ALOGE("%s failed, error code = %d", __func__, res);
-    }
-    return (jint)res;
-}
-
-static jint native_deleteTagData(JNIEnv* env, jobject clazz, jint tagNum, jint uid) {
-    uid_t callingUid = getuid();
-    int res = mTc.deleteTagData(tagNum, (uid_t)uid, callingUid);
-    if (res) {
-      ALOGE("%s failed, error code = %d", __func__, res);
-    }
-    return (jint)res;
-}
-
 /*
  * JNI registration.
  */
@@ -250,10 +232,6 @@
     (void*)native_swapActiveStatsMap},
     {"native_setPermissionForUids", "(I[I)V",
     (void*)native_setPermissionForUids},
-    {"native_setCounterSet", "(II)I",
-    (void*)native_setCounterSet},
-    {"native_deleteTagData", "(II)I",
-    (void*)native_deleteTagData},
 };
 // clang-format on
 
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 5981906..1cbfd94 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -54,7 +54,6 @@
 using base::StringPrintf;
 using base::unique_fd;
 using bpf::BpfMap;
-using bpf::OVERFLOW_COUNTERSET;
 using bpf::synchronizeKernelRCU;
 using netdutils::DumpWriter;
 using netdutils::getIfaceList;
@@ -239,99 +238,6 @@
     return netdutils::status::ok;
 }
 
-int TrafficController::setCounterSet(int counterSetNum, uid_t uid, uid_t callingUid) {
-    if (counterSetNum < 0 || counterSetNum >= OVERFLOW_COUNTERSET) return -EINVAL;
-
-    std::lock_guard guard(mMutex);
-    if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
-
-    // The default counter set for all uid is 0, so deleting the current counterset for that uid
-    // will automatically set it to 0.
-    if (counterSetNum == 0) {
-        Status res = mUidCounterSetMap.deleteValue(uid);
-        if (isOk(res) || (!isOk(res) && res.code() == ENOENT)) {
-            return 0;
-        } else {
-            ALOGE("Failed to delete the counterSet: %s\n", strerror(res.code()));
-            return -res.code();
-        }
-    }
-    uint8_t tmpCounterSetNum = (uint8_t)counterSetNum;
-    Status res = mUidCounterSetMap.writeValue(uid, tmpCounterSetNum, BPF_ANY);
-    if (!isOk(res)) {
-        ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(res.code()),
-              mUidCounterSetMap.getMap().get());
-        return -res.code();
-    }
-    return 0;
-}
-
-// This method only get called by system_server when an app get uinstalled, it
-// is called inside removeUidsLocked() while holding mStatsLock. So it is safe
-// to iterate and modify the stats maps.
-int TrafficController::deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) {
-    std::lock_guard guard(mMutex);
-    if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
-
-    // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
-    // the tags related to the uid if the tag is 0.
-    const auto deleteMatchedCookieEntries = [uid, tag](const uint64_t& key,
-                                                       const UidTagValue& value,
-                                                       BpfMap<uint64_t, UidTagValue>& map) {
-        if (value.uid == uid && (value.tag == tag || tag == 0)) {
-            auto res = map.deleteValue(key);
-            if (res.ok() || (res.error().code() == ENOENT)) {
-                return base::Result<void>();
-            }
-            ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
-                  strerror(res.error().code()));
-        }
-        // Move forward to next cookie in the map.
-        return base::Result<void>();
-    };
-    mCookieTagMap.iterateWithValue(deleteMatchedCookieEntries);
-    // Now we go through the Tag stats map and delete the data entry with correct uid and tag
-    // combination. Or all tag stats under that uid if the target tag is 0.
-    const auto deleteMatchedUidTagEntries = [uid, tag](const StatsKey& key,
-                                                       BpfMap<StatsKey, StatsValue>& map) {
-        if (key.uid == uid && (key.tag == tag || tag == 0)) {
-            auto res = map.deleteValue(key);
-            if (res.ok() || (res.error().code() == ENOENT)) {
-                //Entry is deleted, use the current key to get a new nextKey;
-                return base::Result<void>();
-            }
-            ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", key.uid, key.tag,
-                  strerror(res.error().code()));
-        }
-        return base::Result<void>();
-    };
-    mStatsMapB.iterate(deleteMatchedUidTagEntries);
-    mStatsMapA.iterate(deleteMatchedUidTagEntries);
-    // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
-    // need to delete the stats stored in uidStatsMap and counterSet map.
-    if (tag != 0) return 0;
-
-    auto res = mUidCounterSetMap.deleteValue(uid);
-    if (!res.ok() && res.error().code() != ENOENT) {
-        ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag,
-              strerror(res.error().code()));
-    }
-
-    auto deleteAppUidStatsEntry = [uid](const uint32_t& key,
-                                        BpfMap<uint32_t, StatsValue>& map) -> base::Result<void> {
-        if (key == uid) {
-            auto res = map.deleteValue(key);
-            if (res.ok() || (res.error().code() == ENOENT)) {
-                return {};
-            }
-            ALOGE("Failed to delete data(uid=%u): %s", key, strerror(res.error().code()));
-        }
-        return {};
-    };
-    mAppUidStatsMap.iterate(deleteAppUidStatsEntry);
-    return 0;
-}
-
 int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
     IfaceValue iface;
     if (ifaceIndex == 0) {
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index d0eca34..9529cae 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -55,7 +55,6 @@
 constexpr uid_t TEST_UID3 = 98765;
 constexpr uint32_t TEST_TAG = 42;
 constexpr uint32_t TEST_COUNTERSET = 1;
-constexpr uint32_t DEFAULT_COUNTERSET = 0;
 
 #define ASSERT_VALID(x) ASSERT_TRUE((x).isValid())
 
@@ -64,7 +63,6 @@
     TrafficControllerTest() {}
     TrafficController mTc;
     BpfMap<uint64_t, UidTagValue> mFakeCookieTagMap;
-    BpfMap<uint32_t, uint8_t> mFakeUidCounterSetMap;
     BpfMap<uint32_t, StatsValue> mFakeAppUidStatsMap;
     BpfMap<StatsKey, StatsValue> mFakeStatsMapA;
     BpfMap<uint32_t, uint8_t> mFakeConfigurationMap;
@@ -79,10 +77,6 @@
                                           TEST_MAP_SIZE, 0));
         ASSERT_VALID(mFakeCookieTagMap);
 
-        mFakeUidCounterSetMap.reset(
-            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
-        ASSERT_VALID(mFakeUidCounterSetMap);
-
         mFakeAppUidStatsMap.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(StatsValue),
                                             TEST_MAP_SIZE, 0));
         ASSERT_VALID(mFakeAppUidStatsMap);
@@ -104,8 +98,6 @@
 
         mTc.mCookieTagMap.reset(dupFd(mFakeCookieTagMap.getMap()));
         ASSERT_VALID(mTc.mCookieTagMap);
-        mTc.mUidCounterSetMap.reset(dupFd(mFakeUidCounterSetMap.getMap()));
-        ASSERT_VALID(mTc.mUidCounterSetMap);
         mTc.mAppUidStatsMap.reset(dupFd(mFakeAppUidStatsMap.getMap()));
         ASSERT_VALID(mTc.mAppUidStatsMap);
         mTc.mStatsMapA.reset(dupFd(mFakeStatsMapA.getMap()));
@@ -132,8 +124,6 @@
         EXPECT_RESULT_OK(mFakeCookieTagMap.writeValue(cookie, cookieMapkey, BPF_ANY));
         *key = {.uid = uid, .tag = tag, .counterSet = TEST_COUNTERSET, .ifaceIndex = 1};
         StatsValue statsMapValue = {.rxPackets = 1, .rxBytes = 100};
-        uint8_t counterSet = TEST_COUNTERSET;
-        EXPECT_RESULT_OK(mFakeUidCounterSetMap.writeValue(uid, counterSet, BPF_ANY));
         EXPECT_RESULT_OK(mFakeStatsMapA.writeValue(*key, statsMapValue, BPF_ANY));
         key->tag = 0;
         EXPECT_RESULT_OK(mFakeStatsMapA.writeValue(*key, statsMapValue, BPF_ANY));
@@ -259,9 +249,6 @@
         EXPECT_RESULT_OK(cookieMapResult);
         EXPECT_EQ(uid, cookieMapResult.value().uid);
         EXPECT_EQ(tag, cookieMapResult.value().tag);
-        Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-        EXPECT_RESULT_OK(counterSetResult);
-        EXPECT_EQ(TEST_COUNTERSET, counterSetResult.value());
         Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
         EXPECT_RESULT_OK(statsMapResult);
         EXPECT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
@@ -289,157 +276,6 @@
 
 };
 
-TEST_F(TrafficControllerTest, TestSetCounterSet) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    ASSERT_EQ(0, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, callingUid));
-    uid_t uid = TEST_UID;
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_EQ(0, mTc.setCounterSet(DEFAULT_COUNTERSET, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    expectMapEmpty(mFakeUidCounterSetMap);
-}
-
-TEST_F(TrafficControllerTest, TestSetCounterSetWithoutPermission) {
-    ASSERT_EQ(-EPERM, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, TEST_UID2));
-    uid_t uid = TEST_UID;
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    expectMapEmpty(mFakeUidCounterSetMap);
-}
-
-TEST_F(TrafficControllerTest, TestSetInvalidCounterSet) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    ASSERT_GT(0, mTc.setCounterSet(OVERFLOW_COUNTERSET, TEST_UID, callingUid));
-    uid_t uid = TEST_UID;
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    expectMapEmpty(mFakeUidCounterSetMap);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteTagDataWithoutPermission) {
-    uint64_t cookie = 1;
-    uid_t uid = TEST_UID;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey;
-    populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
-    ASSERT_EQ(-EPERM, mTc.deleteTagData(0, TEST_UID, TEST_UID2));
-
-    expectFakeStatsUnchanged(cookie, tag, uid, tagStatsMapKey);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteTagData) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie = 1;
-    uid_t uid = TEST_UID;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey;
-    populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
-    ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie).ok());
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey).ok());
-    tagStatsMapKey.tag = 0;
-    Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey);
-    ASSERT_RESULT_OK(statsMapResult);
-    ASSERT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-    auto appStatsResult = mFakeAppUidStatsMap.readValue(TEST_UID);
-    ASSERT_RESULT_OK(appStatsResult);
-    ASSERT_EQ((uint64_t)1, appStatsResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie = 1;
-    uid_t uid = TEST_UID;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey;
-    populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
-    ASSERT_EQ(0, mTc.deleteTagData(0, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie).ok());
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid).ok());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey).ok());
-    tagStatsMapKey.tag = 0;
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey).ok());
-    ASSERT_FALSE(mFakeAppUidStatsMap.readValue(TEST_UID).ok());
-}
-
-TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie1 = 1;
-    uint64_t cookie2 = 2;
-    uid_t uid = TEST_UID;
-    uint32_t tag1 = TEST_TAG;
-    uint32_t tag2 = TEST_TAG + 1;
-    StatsKey tagStatsMapKey1;
-    StatsKey tagStatsMapKey2;
-    populateFakeStats(cookie1, uid, tag1, &tagStatsMapKey1);
-    populateFakeStats(cookie2, uid, tag2, &tagStatsMapKey2);
-    ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie1).ok());
-    Result<UidTagValue> cookieMapResult = mFakeCookieTagMap.readValue(cookie2);
-    ASSERT_RESULT_OK(cookieMapResult);
-    ASSERT_EQ(TEST_UID, cookieMapResult.value().uid);
-    ASSERT_EQ(TEST_TAG + 1, cookieMapResult.value().tag);
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey1).ok());
-    Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey2);
-    ASSERT_RESULT_OK(statsMapResult);
-    ASSERT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-}
-
-TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
-    uid_t callingUid = TEST_UID2;
-    addPrivilegedUid(callingUid);
-    uint64_t cookie1 = 1;
-    uint64_t cookie2 = 2;
-    uid_t uid1 = TEST_UID;
-    uid_t uid2 = TEST_UID + 1;
-    uint32_t tag = TEST_TAG;
-    StatsKey tagStatsMapKey1;
-    StatsKey tagStatsMapKey2;
-    populateFakeStats(cookie1, uid1, tag, &tagStatsMapKey1);
-    populateFakeStats(cookie2, uid2, tag, &tagStatsMapKey2);
-
-    // Delete the stats of one of the uid. Check if it is properly collected by
-    // removedStats.
-    ASSERT_EQ(0, mTc.deleteTagData(0, uid2, callingUid));
-    ASSERT_FALSE(mFakeCookieTagMap.readValue(cookie2).ok());
-    Result<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid1);
-    ASSERT_RESULT_OK(counterSetResult);
-    ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
-    ASSERT_FALSE(mFakeUidCounterSetMap.readValue(uid2).ok());
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey2).ok());
-    tagStatsMapKey2.tag = 0;
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey2).ok());
-    ASSERT_FALSE(mFakeAppUidStatsMap.readValue(uid2).ok());
-    tagStatsMapKey1.tag = 0;
-    Result<StatsValue> statsMapResult = mFakeStatsMapA.readValue(tagStatsMapKey1);
-    ASSERT_RESULT_OK(statsMapResult);
-    ASSERT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
-    auto appStatsResult = mFakeAppUidStatsMap.readValue(uid1);
-    ASSERT_RESULT_OK(appStatsResult);
-    ASSERT_EQ((uint64_t)1, appStatsResult.value().rxPackets);
-    ASSERT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
-
-    // Delete the stats of the other uid.
-    ASSERT_EQ(0, mTc.deleteTagData(0, uid1, callingUid));
-    ASSERT_FALSE(mFakeStatsMapA.readValue(tagStatsMapKey1).ok());
-    ASSERT_FALSE(mFakeAppUidStatsMap.readValue(uid1).ok());
-}
-
 TEST_F(TrafficControllerTest, TestUpdateOwnerMapEntry) {
     uint32_t uid = TEST_UID;
     ASSERT_TRUE(isOk(mTc.updateOwnerMapEntry(STANDBY_MATCH, uid, DENY, DENYLIST)));
diff --git a/service/native/include/TrafficController.h b/service/native/include/TrafficController.h
index e741dd6..6fe117f 100644
--- a/service/native/include/TrafficController.h
+++ b/service/native/include/TrafficController.h
@@ -40,18 +40,6 @@
      */
     netdutils::Status start();
 
-    int setCounterSet(int counterSetNum, uid_t uid, uid_t callingUid) EXCLUDES(mMutex);
-
-    /*
-     * When deleting a tag data, the qtaguid module will grab the spinlock of each
-     * related rb_tree one by one and delete the tag information, counterSet
-     * information, iface stats information and uid stats information one by one.
-     * The new eBPF implementation is done similiarly by removing the entry on
-     * each map one by one. And deleting processes are also protected by the
-     * spinlock of the map. So no additional lock is required.
-     */
-    int deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) EXCLUDES(mMutex);
-
     /*
      * Swap the stats map config from current active stats map to the idle one.
      */
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 7a3bab3..ddee275 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -273,32 +273,6 @@
         native_setPermissionForUids(permissions, uids);
     }
 
-    /**
-     * Set counter set for uid
-     *
-     * @param counterSet either SET_DEFAULT or SET_FOREGROUND
-     * @param uid        uid to foreground/background
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *                                  cause of the failure.
-     */
-    public void setCounterSet(final int counterSet, final int uid) {
-        final int err = native_setCounterSet(counterSet, uid);
-        maybeThrow(err, "setCounterSet failed");
-    }
-
-    /**
-     * Reset Uid stats
-     *
-     * @param tag default 0
-     * @param uid given uid to be clear
-     * @throws ServiceSpecificException in case of failure, with an error code indicating the
-     *                                  cause of the failure.
-     */
-    public void deleteTagData(final int tag, final int uid) {
-        final int err = native_deleteTagData(tag, uid);
-        maybeThrow(err, "deleteTagData failed");
-    }
-
     private static native void native_init();
     private native int native_addNaughtyApp(int uid);
     private native int native_removeNaughtyApp(int uid);
@@ -311,6 +285,4 @@
     private native int native_removeUidInterfaceRules(int[] uids);
     private native int native_swapActiveStatsMap();
     private native void native_setPermissionForUids(int permissions, int[] uids);
-    private native int native_setCounterSet(int counterSet, int uid);
-    private native int native_deleteTagData(int tag, int uid);
 }
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 6944ca9..6024a2a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -90,6 +90,7 @@
 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.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.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 libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
 import java.net.Inet4Address;
@@ -709,6 +713,11 @@
     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 @@
      */
     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 @@
     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 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 @@
         } catch (ErrnoException e) {
             loge("Unable to create DscpPolicyTracker");
         }
+
+        mIngressRateLimit = ConnectivitySettingsManager.getIngressRateLimitInBytesPerSecond(
+                mContext);
     }
 
     private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -1611,6 +1683,11 @@
         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 @@
         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() {
@@ -4138,6 +4221,11 @@
             // 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();
@@ -5205,6 +5293,9 @@
                     final long timeMs = ((Long) msg.obj).longValue();
                     mMultinetworkPolicyTracker.setTestAllowBadWifiUntil(timeMs);
                     break;
+                case EVENT_INGRESS_RATE_LIMIT_CHANGED:
+                    handleIngressRateLimitChanged();
+                    break;
             }
         }
     }
@@ -8901,6 +8992,19 @@
             // 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
@@ -10561,6 +10665,39 @@
         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.");
diff --git a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
index ebaa787..8d8958d 100644
--- a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
+++ b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
@@ -39,6 +39,7 @@
 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.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 @@
                 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)
+        }
+    }
 }
\ No newline at end of file
diff --git a/tests/common/java/android/net/NetworkAgentConfigTest.kt b/tests/common/java/android/net/NetworkAgentConfigTest.kt
index 11d3ba0..e5db09f 100644
--- a/tests/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/common/java/android/net/NetworkAgentConfigTest.kt
@@ -51,7 +51,7 @@
                 setBypassableVpn(true)
             }
             if (isAtLeastT()) {
-                setExcludeLocalRoutesVpn(true)
+                setLocalRoutesExcludedForVpn(true)
                 setVpnRequiresValidation(true)
             }
         }.build()
@@ -75,7 +75,7 @@
                 setBypassableVpn(true)
             }
             if (isAtLeastT()) {
-                setExcludeLocalRoutesVpn(true)
+                setLocalRoutesExcludedForVpn(true)
                 setVpnRequiresValidation(true)
             }
         }.build()
@@ -87,7 +87,7 @@
         assertTrue(config.isUnvalidatedConnectivityAcceptable())
         assertEquals("TEST_NETWORK", config.getLegacyTypeName())
         if (isAtLeastT()) {
-            assertTrue(config.getExcludeLocalRouteVpn())
+            assertTrue(config.areLocalRoutesExcludedForVpn())
             assertTrue(config.getVpnRequiresValidation())
         }
         if (isAtLeastS()) {
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 7ae5333..fde7bac 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -27,7 +27,6 @@
         "libbase",
         "libbinder",
         "libbpf_bcc",
-        "libbpf_android",
         "libc++",
         "libcgrouprc",
         "libcrypto",
diff --git a/tests/unit/java/android/net/Ikev2VpnProfileTest.java b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
index a151f03..8559c20 100644
--- a/tests/unit/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/unit/java/android/net/Ikev2VpnProfileTest.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -264,17 +266,17 @@
     }
 
 
-    // TODO: Refer to Build.VERSION_CODES.SC_V2 when it's available in AOSP
-    @DevSdkIgnoreRule.IgnoreUpTo(32)
+    // TODO: Refer to Build.VERSION_CODES.SC_V2 when it's available in AOSP and mainline branch
+    @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
     @Test
     public void testBuildExcludeLocalRoutesSet() throws Exception {
         final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
         builder.setAuthPsk(PSK_BYTES);
-        builder.setExcludeLocalRoutes(true);
+        builder.setLocalRoutesExcluded(true);
 
         final Ikev2VpnProfile profile = builder.build();
         assertNotNull(profile);
-        assertTrue(profile.getExcludeLocalRoutes());
+        assertTrue(profile.areLocalRoutesExcluded());
 
         builder.setBypassable(false);
         try {
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index e233e62..16b3d5a 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -179,7 +179,6 @@
 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.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 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 @@
         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 @@
                 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));
+    }
 }
diff --git a/tests/unit/java/com/android/server/NetworkManagementServiceTest.java b/tests/unit/java/com/android/server/NetworkManagementServiceTest.java
index 0c58582..a3b0e7c 100644
--- a/tests/unit/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/unit/java/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,11 @@
 
 package com.android.server;
 
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
 import static android.util.DebugUtils.valueToString;
 
 import static org.junit.Assert.assertEquals;
@@ -277,31 +282,38 @@
         isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
         isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
         isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
-        expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
+        expected.put(FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
         // Powersaver chain
         final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
         isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
         isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
         isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
-        expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
+        expected.put(FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
         // Standby chain
         final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
         isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
         isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
         isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
-        expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
+        expected.put(FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
         // Restricted mode chain
         final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
         isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
         isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
         isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
-        expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
+        expected.put(FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
+        // Low Power Standby chain
+        final ArrayMap<Integer, Boolean> isRestrictedForLowPowerStandby = new ArrayMap<>();
+        isRestrictedForLowPowerStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForLowPowerStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForLowPowerStandby.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(FIREWALL_CHAIN_LOW_POWER_STANDBY, isRestrictedForLowPowerStandby);
 
         final int[] chains = {
-                INetd.FIREWALL_CHAIN_STANDBY,
-                INetd.FIREWALL_CHAIN_POWERSAVE,
-                INetd.FIREWALL_CHAIN_DOZABLE,
-                INetd.FIREWALL_CHAIN_RESTRICTED
+                FIREWALL_CHAIN_STANDBY,
+                FIREWALL_CHAIN_POWERSAVE,
+                FIREWALL_CHAIN_DOZABLE,
+                FIREWALL_CHAIN_RESTRICTED,
+                FIREWALL_CHAIN_LOW_POWER_STANDBY
         };
         final int[] states = {
                 INetd.FIREWALL_RULE_ALLOW,
diff --git a/tests/unit/jni/Android.bp b/tests/unit/jni/Android.bp
index 04ba98f..616da81 100644
--- a/tests/unit/jni/Android.bp
+++ b/tests/unit/jni/Android.bp
@@ -21,7 +21,6 @@
     ],
 
     shared_libs: [
-        "libbpf_android",
         "liblog",
         "libnativehelper",
         "libnetdutils",