Rename BpfNetMapsReader to NetworkStackBpfNetMaps

BpfNetMapsReader is loaded to bootclasspath. So this class should not
contain unnecessary codes.
To make this clear, this CL renames to NetowrkStackBpfNetMaps and add
comments

Bug: 328732146
Test: TH
Change-Id: I557627c9fae087eb6119c2ae31d46526fa9e5d7e
This commit is contained in:
Motomu Utsumi 2024-03-15 18:48:29 +09:00
commit fc504042f6
4 changed files with 29 additions and 26 deletions

View file

@ -6286,7 +6286,7 @@ public class ConnectivityManager {
if (!SdkLevel.isAtLeastU()) {
Log.wtf(TAG, "isUidNetworkingBlocked is not supported on pre-U devices");
}
final BpfNetMapsReader reader = BpfNetMapsReader.getInstance();
final NetworkStackBpfNetMaps reader = NetworkStackBpfNetMaps.getInstance();
// Note that before V, the data saver status in bpf is written by ConnectivityService
// when receiving {@link #ACTION_RESTRICT_BACKGROUND_CHANGED}. Thus,
// the status is not synchronized.

View file

@ -0,0 +1,290 @@
/*
* Copyright (C) 2023 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;
import static android.net.BpfNetMapsConstants.CONFIGURATION_MAP_PATH;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_MAP_PATH;
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH;
import static android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY;
import static android.net.BpfNetMapsUtils.getMatchByFirewallChain;
import static android.net.BpfNetMapsUtils.isFirewallAllowList;
import static android.net.BpfNetMapsUtils.throwIfPreT;
import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
import android.annotation.NonNull;
import android.annotation.RequiresApi;
import android.os.Build;
import android.os.ServiceSpecificException;
import android.system.ErrnoException;
import android.system.Os;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.BpfMap;
import com.android.net.module.util.IBpfMap;
import com.android.net.module.util.Struct.S32;
import com.android.net.module.util.Struct.U32;
import com.android.net.module.util.Struct.U8;
/**
* A helper class to *read* java BpfMaps for network stack.
* BpfMap operations that are not used from network stack should be in
* {@link com.android.server.BpfNetMaps}
* @hide
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU) // BPF maps were only mainlined in T
public class NetworkStackBpfNetMaps {
private static final String TAG = NetworkStackBpfNetMaps.class.getSimpleName();
// Locally store the handle of bpf maps. The FileDescriptors are statically cached inside the
// BpfMap implementation.
// Bpf map to store various networking configurations, the format of the value is different
// for different keys. See BpfNetMapsConstants#*_CONFIGURATION_KEY for keys.
private final IBpfMap<S32, U32> mConfigurationMap;
// Bpf map to store per uid traffic control configurations.
// See {@link UidOwnerValue} for more detail.
private final IBpfMap<S32, UidOwnerValue> mUidOwnerMap;
private final IBpfMap<S32, U8> mDataSaverEnabledMap;
private final Dependencies mDeps;
// Bitmaps for calculating whether a given uid is blocked by firewall chains.
private static final long sMaskDropIfSet;
private static final long sMaskDropIfUnset;
static {
long maskDropIfSet = 0L;
long maskDropIfUnset = 0L;
for (int chain : BpfNetMapsConstants.ALLOW_CHAINS) {
final long match = getMatchByFirewallChain(chain);
maskDropIfUnset |= match;
}
for (int chain : BpfNetMapsConstants.DENY_CHAINS) {
final long match = getMatchByFirewallChain(chain);
maskDropIfSet |= match;
}
sMaskDropIfSet = maskDropIfSet;
sMaskDropIfUnset = maskDropIfUnset;
}
private static class SingletonHolder {
static final NetworkStackBpfNetMaps sInstance = new NetworkStackBpfNetMaps();
}
@NonNull
public static NetworkStackBpfNetMaps getInstance() {
return SingletonHolder.sInstance;
}
private NetworkStackBpfNetMaps() {
this(new Dependencies());
}
// While the production code uses the singleton to optimize for performance and deal with
// concurrent access, the test needs to use a non-static approach for dependency injection and
// mocking virtual bpf maps.
@VisibleForTesting
public NetworkStackBpfNetMaps(@NonNull Dependencies deps) {
if (!SdkLevel.isAtLeastT()) {
throw new UnsupportedOperationException(
NetworkStackBpfNetMaps.class.getSimpleName()
+ " is not supported below Android T");
}
mDeps = deps;
mConfigurationMap = mDeps.getConfigurationMap();
mUidOwnerMap = mDeps.getUidOwnerMap();
mDataSaverEnabledMap = mDeps.getDataSaverEnabledMap();
}
/**
* Dependencies of BpfNetMapReader, for injection in tests.
*/
@VisibleForTesting
public static class Dependencies {
/** Get the configuration map. */
public IBpfMap<S32, U32> getConfigurationMap() {
try {
return new BpfMap<>(CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDONLY,
S32.class, U32.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open configuration map", e);
}
}
/** Get the uid owner map. */
public IBpfMap<S32, UidOwnerValue> getUidOwnerMap() {
try {
return new BpfMap<>(UID_OWNER_MAP_PATH, BpfMap.BPF_F_RDONLY,
S32.class, UidOwnerValue.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open uid owner map", e);
}
}
/** Get the data saver enabled map. */
public IBpfMap<S32, U8> getDataSaverEnabledMap() {
try {
return new BpfMap<>(DATA_SAVER_ENABLED_MAP_PATH, BpfMap.BPF_F_RDONLY, S32.class,
U8.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open data saver enabled map", e);
}
}
}
/**
* Get the specified firewall chain's status.
*
* @param chain target chain
* @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
* @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public boolean isChainEnabled(final int chain) {
return isChainEnabled(mConfigurationMap, chain);
}
/**
* Get firewall rule of specified firewall chain on specified uid.
*
* @param chain target chain
* @param uid target uid
* @return either {@link ConnectivityManager#FIREWALL_RULE_ALLOW} or
* {@link ConnectivityManager#FIREWALL_RULE_DENY}.
* @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public int getUidRule(final int chain, final int uid) {
return getUidRule(mUidOwnerMap, chain, uid);
}
/**
* Get the specified firewall chain's status.
*
* @param configurationMap target configurationMap
* @param chain target chain
* @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
* @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public static boolean isChainEnabled(
final IBpfMap<S32, U32> configurationMap, final int chain) {
throwIfPreT("isChainEnabled is not available on pre-T devices");
final long match = getMatchByFirewallChain(chain);
try {
final U32 config = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
return (config.val & match) != 0;
} catch (ErrnoException e) {
throw new ServiceSpecificException(e.errno,
"Unable to get firewall chain status: " + Os.strerror(e.errno));
}
}
/**
* Get firewall rule of specified firewall chain on specified uid.
*
* @param uidOwnerMap target uidOwnerMap.
* @param chain target chain.
* @param uid target uid.
* @return either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
* @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public static int getUidRule(final IBpfMap<S32, UidOwnerValue> uidOwnerMap,
final int chain, final int uid) {
throwIfPreT("getUidRule is not available on pre-T devices");
final long match = getMatchByFirewallChain(chain);
final boolean isAllowList = isFirewallAllowList(chain);
try {
final UidOwnerValue uidMatch = uidOwnerMap.getValue(new S32(uid));
final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0;
return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
} catch (ErrnoException e) {
throw new ServiceSpecificException(e.errno,
"Unable to get uid rule status: " + Os.strerror(e.errno));
}
}
/**
* Return whether the network is blocked by firewall chains for the given uid.
*
* @param uid The target uid.
* @param isNetworkMetered Whether the target network is metered.
* @param isDataSaverEnabled Whether the data saver is enabled.
*
* @return True if the network is blocked. Otherwise, false.
* @throws ServiceSpecificException if the read fails.
*
* @hide
*/
public boolean isUidNetworkingBlocked(final int uid, boolean isNetworkMetered,
boolean isDataSaverEnabled) {
throwIfPreT("isUidBlockedByFirewallChains is not available on pre-T devices");
final long uidRuleConfig;
final long uidMatch;
try {
uidRuleConfig = mConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val;
final UidOwnerValue value = mUidOwnerMap.getValue(new S32(uid));
uidMatch = (value != null) ? value.rule : 0L;
} catch (ErrnoException e) {
throw new ServiceSpecificException(e.errno,
"Unable to get firewall chain status: " + Os.strerror(e.errno));
}
final boolean blockedByAllowChains = 0 != (uidRuleConfig & ~uidMatch & sMaskDropIfUnset);
final boolean blockedByDenyChains = 0 != (uidRuleConfig & uidMatch & sMaskDropIfSet);
if (blockedByAllowChains || blockedByDenyChains) {
return true;
}
if (!isNetworkMetered) return false;
if ((uidMatch & PENALTY_BOX_MATCH) != 0) return true;
if ((uidMatch & HAPPY_BOX_MATCH) != 0) return false;
return isDataSaverEnabled;
}
/**
* Get Data Saver enabled or disabled
*
* @return whether Data Saver is enabled or disabled.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public boolean getDataSaverEnabled() {
throwIfPreT("getDataSaverEnabled is not available on pre-T devices");
try {
return mDataSaverEnabledMap.getValue(DATA_SAVER_ENABLED_KEY).val == DATA_SAVER_ENABLED;
} catch (ErrnoException e) {
throw new ServiceSpecificException(e.errno, "Unable to get data saver: "
+ Os.strerror(e.errno));
}
}
}

View file

@ -49,8 +49,8 @@ import static com.android.server.ConnectivityStatsLog.NETWORK_BPF_MAP_INFO;
import android.app.StatsManager;
import android.content.Context;
import android.net.BpfNetMapsReader;
import android.net.INetd;
import android.net.NetworkStackBpfNetMaps;
import android.net.UidOwnerValue;
import android.os.Build;
import android.os.RemoteException;
@ -535,14 +535,11 @@ public class BpfNetMaps {
* @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*
* @deprecated Use {@link BpfNetMapsReader#isChainEnabled} instead.
*/
// TODO: Migrate the callers to use {@link BpfNetMapsReader#isChainEnabled} instead.
@Deprecated
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isChainEnabled(final int childChain) {
return BpfNetMapsReader.isChainEnabled(sConfigurationMap, childChain);
return NetworkStackBpfNetMaps.isChainEnabled(sConfigurationMap, childChain);
}
private Set<Integer> asSet(final int[] uids) {
@ -635,12 +632,9 @@ public class BpfNetMaps {
* @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*
* @deprecated use {@link BpfNetMapsReader#getUidRule} instead.
*/
// TODO: Migrate the callers to use {@link BpfNetMapsReader#getUidRule} instead.
public int getUidRule(final int childChain, final int uid) {
return BpfNetMapsReader.getUidRule(sUidOwnerMap, childChain, uid);
return NetworkStackBpfNetMaps.getUidRule(sUidOwnerMap, childChain, uid);
}
private Set<Integer> getUidsMatchEnabled(final int childChain) throws ErrnoException {

View file

@ -0,0 +1,229 @@
/*
* Copyright (C) 2023 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
import android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED
import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED
import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY
import android.net.BpfNetMapsConstants.DOZABLE_MATCH
import android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH
import android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH
import android.net.BpfNetMapsConstants.STANDBY_MATCH
import android.net.BpfNetMapsConstants.UID_RULES_CONFIGURATION_KEY
import android.net.BpfNetMapsUtils.getMatchByFirewallChain
import android.os.Build.VERSION_CODES
import com.android.net.module.util.IBpfMap
import com.android.net.module.util.Struct.S32
import com.android.net.module.util.Struct.U32
import com.android.net.module.util.Struct.U8
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.TestBpfMap
import java.lang.reflect.Modifier
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
private const val TEST_UID1 = 1234
private const val TEST_UID2 = TEST_UID1 + 1
private const val TEST_UID3 = TEST_UID2 + 1
private const val NO_IIF = 0
// pre-T devices does not support Bpf.
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(VERSION_CODES.S_V2)
class NetworkStackBpfNetMapsTest {
@Rule
@JvmField
val ignoreRule = DevSdkIgnoreRule()
private val testConfigurationMap: IBpfMap<S32, U32> = TestBpfMap()
private val testUidOwnerMap: IBpfMap<S32, UidOwnerValue> = TestBpfMap()
private val testDataSaverEnabledMap: IBpfMap<S32, U8> = TestBpfMap()
private val bpfNetMapsReader = NetworkStackBpfNetMaps(
TestDependencies(testConfigurationMap, testUidOwnerMap, testDataSaverEnabledMap)
)
class TestDependencies(
private val configMap: IBpfMap<S32, U32>,
private val uidOwnerMap: IBpfMap<S32, UidOwnerValue>,
private val dataSaverEnabledMap: IBpfMap<S32, U8>
) : NetworkStackBpfNetMaps.Dependencies() {
override fun getConfigurationMap() = configMap
override fun getUidOwnerMap() = uidOwnerMap
override fun getDataSaverEnabledMap() = dataSaverEnabledMap
}
private fun doTestIsChainEnabled(chain: Int) {
testConfigurationMap.updateEntry(
UID_RULES_CONFIGURATION_KEY,
U32(getMatchByFirewallChain(chain))
)
assertTrue(bpfNetMapsReader.isChainEnabled(chain))
testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
assertFalse(bpfNetMapsReader.isChainEnabled(chain))
}
@Test
@Throws(Exception::class)
fun testIsChainEnabled() {
doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE)
doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY)
doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE)
doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_RESTRICTED)
doTestIsChainEnabled(ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY)
}
@Test
fun testFirewallChainList() {
// Verify that when a firewall chain constant is added, it should also be included in
// firewall chain list.
val declaredChains = ConnectivityManager::class.java.declaredFields.filter {
Modifier.isStatic(it.modifiers) && it.name.startsWith("FIREWALL_CHAIN_")
}
// Verify the size matches, this also verifies no common item in allow and deny chains.
assertEquals(
BpfNetMapsConstants.ALLOW_CHAINS.size +
BpfNetMapsConstants.DENY_CHAINS.size,
declaredChains.size
)
declaredChains.forEach {
assertTrue(
BpfNetMapsConstants.ALLOW_CHAINS.contains(it.get(null)) ||
BpfNetMapsConstants.DENY_CHAINS.contains(it.get(null))
)
}
}
private fun mockChainEnabled(chain: Int, enabled: Boolean) {
val config = testConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).`val`
val newConfig = if (enabled) {
config or getMatchByFirewallChain(chain)
} else {
config and getMatchByFirewallChain(chain).inv()
}
testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(newConfig))
}
fun isUidNetworkingBlocked(uid: Int, metered: Boolean = false, dataSaver: Boolean = false) =
bpfNetMapsReader.isUidNetworkingBlocked(uid, metered, dataSaver)
@Test
fun testIsUidNetworkingBlockedByFirewallChains_allowChain() {
// With everything disabled by default, verify the return value is false.
testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
assertFalse(isUidNetworkingBlocked(TEST_UID1))
// Enable dozable chain but does not provide allowed list. Verify the network is blocked
// for all uids.
mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, true)
assertTrue(isUidNetworkingBlocked(TEST_UID1))
assertTrue(isUidNetworkingBlocked(TEST_UID2))
// Add uid1 to dozable allowed list. Verify the network is not blocked for uid1, while
// uid2 is blocked.
testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, DOZABLE_MATCH))
assertFalse(isUidNetworkingBlocked(TEST_UID1))
assertTrue(isUidNetworkingBlocked(TEST_UID2))
}
@Test
fun testIsUidNetworkingBlockedByFirewallChains_denyChain() {
// Enable standby chain but does not provide denied list. Verify the network is allowed
// for all uids.
testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY, true)
assertFalse(isUidNetworkingBlocked(TEST_UID1))
assertFalse(isUidNetworkingBlocked(TEST_UID2))
// Add uid1 to standby allowed list. Verify the network is blocked for uid1, while
// uid2 is not blocked.
testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, STANDBY_MATCH))
assertTrue(isUidNetworkingBlocked(TEST_UID1))
assertFalse(isUidNetworkingBlocked(TEST_UID2))
}
@Test
fun testIsUidNetworkingBlockedByFirewallChains_blockedWithAllowed() {
// Uids blocked by powersave chain but allowed by standby chain, verify the blocking
// takes higher priority.
testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_POWERSAVE, true)
mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_STANDBY, true)
assertTrue(isUidNetworkingBlocked(TEST_UID1))
}
@IgnoreUpTo(VERSION_CODES.S_V2)
@Test
fun testIsUidNetworkingBlockedByDataSaver() {
// With everything disabled by default, verify the return value is false.
testConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, U32(0))
assertFalse(isUidNetworkingBlocked(TEST_UID1, metered = true))
// Add uid1 to penalty box, verify the network is blocked for uid1, while uid2 is not
// affected.
testUidOwnerMap.updateEntry(S32(TEST_UID1), UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH))
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
// Enable data saver, verify the network is blocked for uid1, uid2, but uid3 in happy box
// is not affected.
testUidOwnerMap.updateEntry(S32(TEST_UID3), UidOwnerValue(NO_IIF, HAPPY_BOX_MATCH))
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true, dataSaver = true))
assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true, dataSaver = true))
assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true, dataSaver = true))
// Add uid1 to happy box as well, verify nothing is changed because penalty box has higher
// priority.
testUidOwnerMap.updateEntry(
S32(TEST_UID1),
UidOwnerValue(NO_IIF, PENALTY_BOX_MATCH or HAPPY_BOX_MATCH)
)
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true, dataSaver = true))
assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true, dataSaver = true))
assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true, dataSaver = true))
// Enable doze mode, verify uid3 is blocked even if it is in happy box.
mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, true)
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true, dataSaver = true))
assertTrue(isUidNetworkingBlocked(TEST_UID2, metered = true, dataSaver = true))
assertTrue(isUidNetworkingBlocked(TEST_UID3, metered = true, dataSaver = true))
// Disable doze mode and data saver, only uid1 which is in penalty box is blocked.
mockChainEnabled(ConnectivityManager.FIREWALL_CHAIN_DOZABLE, false)
assertTrue(isUidNetworkingBlocked(TEST_UID1, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID2, metered = true))
assertFalse(isUidNetworkingBlocked(TEST_UID3, metered = true))
// Make the network non-metered, nothing is blocked.
assertFalse(isUidNetworkingBlocked(TEST_UID1))
assertFalse(isUidNetworkingBlocked(TEST_UID2))
assertFalse(isUidNetworkingBlocked(TEST_UID3))
}
@Test
fun testGetDataSaverEnabled() {
testDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, U8(DATA_SAVER_DISABLED))
assertFalse(bpfNetMapsReader.dataSaverEnabled)
testDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, U8(DATA_SAVER_ENABLED))
assertTrue(bpfNetMapsReader.dataSaverEnabled)
}
}