Write Data Saver setting to BPF map
The information is needed by modules who want to know whether a specific UID is blocked by Data Saver feature. 1. Add a one-element map data_saver_enabled_map. 2. Update current data saver setting to the map. Bug: 288340533 Test: atest FrameworksNetTests:android.net.connectivity.com.android.serv er.BpfNetMapsTest Test: atest bpf_existence_test Change-Id: I981da4b569247c33cba2d365cb6f2691f673474e
This commit is contained in:
parent
6b134f18f4
commit
243301748e
7 changed files with 123 additions and 0 deletions
|
@ -112,6 +112,9 @@ DEFINE_BPF_RINGBUF_EXT(packet_trace_ringbuf, PacketTrace, PACKET_TRACE_BUF_SIZE,
|
|||
BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
|
||||
LOAD_ON_USER, LOAD_ON_USERDEBUG);
|
||||
|
||||
DEFINE_BPF_MAP_RO_NETD(data_saver_enabled_map, ARRAY, uint32_t, bool,
|
||||
DATA_SAVER_ENABLED_MAP_SIZE)
|
||||
|
||||
// iptables xt_bpf programs need to be usable by both netd and netutils_wrappers
|
||||
// selinux contexts, because even non-xt_bpf iptables mutations are implemented as
|
||||
// a full table dump, followed by an update in userspace, and then a reload into the kernel,
|
||||
|
|
|
@ -126,6 +126,7 @@ static const int CONFIGURATION_MAP_SIZE = 2;
|
|||
static const int UID_OWNER_MAP_SIZE = 4000;
|
||||
static const int INGRESS_DISCARD_MAP_SIZE = 100;
|
||||
static const int PACKET_TRACE_BUF_SIZE = 32 * 1024;
|
||||
static const int DATA_SAVER_ENABLED_MAP_SIZE = 1;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
@ -172,6 +173,7 @@ ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilte
|
|||
#define INGRESS_DISCARD_MAP_PATH BPF_NETD_PATH "map_netd_ingress_discard_map"
|
||||
#define PACKET_TRACE_RINGBUF_PATH BPF_NETD_PATH "map_netd_packet_trace_ringbuf"
|
||||
#define PACKET_TRACE_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_packet_trace_enabled_map"
|
||||
#define DATA_SAVER_ENABLED_MAP_PATH BPF_NETD_PATH "map_netd_data_saver_enabled_map"
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
|
|
|
@ -43,8 +43,14 @@ public class BpfNetMapsConstants {
|
|||
"/sys/fs/bpf/netd_shared/map_netd_uid_permission_map";
|
||||
public static final String COOKIE_TAG_MAP_PATH =
|
||||
"/sys/fs/bpf/netd_shared/map_netd_cookie_tag_map";
|
||||
public static final String DATA_SAVER_ENABLED_MAP_PATH =
|
||||
"/sys/fs/bpf/netd_shared/map_netd_data_saver_enabled_map";
|
||||
public static final Struct.S32 UID_RULES_CONFIGURATION_KEY = new Struct.S32(0);
|
||||
public static final Struct.S32 CURRENT_STATS_MAP_CONFIGURATION_KEY = new Struct.S32(1);
|
||||
public static final Struct.S32 DATA_SAVER_ENABLED_KEY = new Struct.S32(0);
|
||||
|
||||
public static final short DATA_SAVER_DISABLED = 0;
|
||||
public static final short DATA_SAVER_ENABLED = 1;
|
||||
|
||||
// LINT.IfChange(match_type)
|
||||
public static final long NO_MATCH = 0;
|
||||
|
|
|
@ -19,6 +19,10 @@ package com.android.server;
|
|||
import static android.net.BpfNetMapsConstants.CONFIGURATION_MAP_PATH;
|
||||
import static android.net.BpfNetMapsConstants.COOKIE_TAG_MAP_PATH;
|
||||
import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY;
|
||||
import static android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED;
|
||||
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.IIF_MATCH;
|
||||
import static android.net.BpfNetMapsConstants.LOCKDOWN_VPN_MATCH;
|
||||
|
@ -130,6 +134,8 @@ public class BpfNetMaps {
|
|||
private static IBpfMap<S32, UidOwnerValue> sUidOwnerMap = null;
|
||||
private static IBpfMap<S32, U8> sUidPermissionMap = null;
|
||||
private static IBpfMap<CookieTagMapKey, CookieTagMapValue> sCookieTagMap = null;
|
||||
// TODO: Add BOOL class and replace U8?
|
||||
private static IBpfMap<S32, U8> sDataSaverEnabledMap = null;
|
||||
|
||||
private static final List<Pair<Integer, String>> PERMISSION_LIST = Arrays.asList(
|
||||
Pair.create(PERMISSION_INTERNET, "PERMISSION_INTERNET"),
|
||||
|
@ -177,6 +183,14 @@ public class BpfNetMaps {
|
|||
sCookieTagMap = cookieTagMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dataSaverEnabledMap for test.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static void setDataSaverEnabledMapForTest(IBpfMap<S32, U8> dataSaverEnabledMap) {
|
||||
sDataSaverEnabledMap = dataSaverEnabledMap;
|
||||
}
|
||||
|
||||
private static IBpfMap<S32, U32> getConfigurationMap() {
|
||||
try {
|
||||
return new BpfMap<>(
|
||||
|
@ -213,6 +227,15 @@ public class BpfNetMaps {
|
|||
}
|
||||
}
|
||||
|
||||
private static IBpfMap<S32, U8> getDataSaverEnabledMap() {
|
||||
try {
|
||||
return new BpfMap<>(
|
||||
DATA_SAVER_ENABLED_MAP_PATH, BpfMap.BPF_F_RDWR, S32.class, U8.class);
|
||||
} catch (ErrnoException e) {
|
||||
throw new IllegalStateException("Cannot open data saver enabled map", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initBpfMaps() {
|
||||
if (sConfigurationMap == null) {
|
||||
sConfigurationMap = getConfigurationMap();
|
||||
|
@ -246,6 +269,15 @@ public class BpfNetMaps {
|
|||
if (sCookieTagMap == null) {
|
||||
sCookieTagMap = getCookieTagMap();
|
||||
}
|
||||
|
||||
if (sDataSaverEnabledMap == null) {
|
||||
sDataSaverEnabledMap = getDataSaverEnabledMap();
|
||||
}
|
||||
try {
|
||||
sDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(DATA_SAVER_DISABLED));
|
||||
} catch (ErrnoException e) {
|
||||
throw new IllegalStateException("Failed to initialize data saver configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -926,6 +958,27 @@ public class BpfNetMaps {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Data Saver enabled or disabled
|
||||
*
|
||||
* @param enable whether Data Saver is enabled or disabled.
|
||||
* @throws UnsupportedOperationException if called on pre-T devices.
|
||||
* @throws ServiceSpecificException in case of failure, with an error code indicating the
|
||||
* cause of the failure.
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
public void setDataSaverEnabled(boolean enable) {
|
||||
throwIfPreT("setDataSaverEnabled is not available on pre-T devices");
|
||||
|
||||
try {
|
||||
final short config = enable ? DATA_SAVER_ENABLED : DATA_SAVER_DISABLED;
|
||||
sDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(config));
|
||||
} catch (ErrnoException e) {
|
||||
throw new ServiceSpecificException(e.errno, "Unable to set data saver: "
|
||||
+ Os.strerror(e.errno));
|
||||
}
|
||||
}
|
||||
|
||||
/** Register callback for statsd to pull atom. */
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
public void setPullAtomCallback(final Context context) {
|
||||
|
@ -1008,6 +1061,15 @@ public class BpfNetMaps {
|
|||
}
|
||||
}
|
||||
|
||||
private void dumpDataSaverConfig(final IndentingPrintWriter pw) {
|
||||
try {
|
||||
final short config = sDataSaverEnabledMap.getValue(DATA_SAVER_ENABLED_KEY).val;
|
||||
// Any non-zero value converted from short to boolean is true by convention.
|
||||
pw.println("sDataSaverEnabledMap: " + (config != DATA_SAVER_DISABLED));
|
||||
} catch (ErrnoException e) {
|
||||
pw.println("Failed to read data saver configuration: " + e);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Dump BPF maps
|
||||
*
|
||||
|
@ -1058,6 +1120,8 @@ public class BpfNetMaps {
|
|||
});
|
||||
BpfDump.dumpMap(sUidPermissionMap, pw, "sUidPermissionMap",
|
||||
(uid, permission) -> uid.val + " " + permissionToString(permission.val));
|
||||
|
||||
dumpDataSaverConfig(pw);
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12556,6 +12556,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.TIRAMISU)
|
||||
@Override
|
||||
public void setDataSaverEnabled(final boolean enable) {
|
||||
enforceNetworkStackOrSettingsPermission();
|
||||
|
@ -12568,6 +12569,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
// Lack of permission or binder errors.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
mBpfNetMaps.setDataSaverEnabled(enable);
|
||||
} catch (ServiceSpecificException | UnsupportedOperationException e) {
|
||||
Log.e(TAG, "Failed to set data saver " + enable + " : " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -94,6 +94,7 @@ static const set<string> MAINLINE_FOR_T_PLUS = {
|
|||
NETD "map_netd_app_uid_stats_map",
|
||||
NETD "map_netd_configuration_map",
|
||||
NETD "map_netd_cookie_tag_map",
|
||||
NETD "map_netd_data_saver_enabled_map",
|
||||
NETD "map_netd_iface_index_name_map",
|
||||
NETD "map_netd_iface_stats_map",
|
||||
NETD "map_netd_ingress_discard_map",
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
package com.android.server;
|
||||
|
||||
import static android.net.BpfNetMapsConstants.CURRENT_STATS_MAP_CONFIGURATION_KEY;
|
||||
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
|
||||
import static android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED;
|
||||
import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED;
|
||||
import static android.net.BpfNetMapsConstants.DOZABLE_MATCH;
|
||||
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
|
||||
import static android.net.BpfNetMapsConstants.IIF_MATCH;
|
||||
|
@ -141,6 +144,7 @@ public final class BpfNetMapsTest {
|
|||
private final IBpfMap<S32, U8> mUidPermissionMap = new TestBpfMap<>(S32.class, U8.class);
|
||||
private final IBpfMap<CookieTagMapKey, CookieTagMapValue> mCookieTagMap =
|
||||
spy(new TestBpfMap<>(CookieTagMapKey.class, CookieTagMapValue.class));
|
||||
private final IBpfMap<S32, U8> mDataSaverEnabledMap = new TestBpfMap<>(S32.class, U8.class);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -155,6 +159,8 @@ public final class BpfNetMapsTest {
|
|||
BpfNetMaps.setUidOwnerMapForTest(mUidOwnerMap);
|
||||
BpfNetMaps.setUidPermissionMapForTest(mUidPermissionMap);
|
||||
BpfNetMaps.setCookieTagMapForTest(mCookieTagMap);
|
||||
BpfNetMaps.setDataSaverEnabledMapForTest(mDataSaverEnabledMap);
|
||||
mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(DATA_SAVER_DISABLED));
|
||||
mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps);
|
||||
}
|
||||
|
||||
|
@ -1155,6 +1161,21 @@ public final class BpfNetMapsTest {
|
|||
assertDumpContains(getDump(), "cookie=123 tag=0x789 uid=456");
|
||||
}
|
||||
|
||||
private void doTestDumpDataSaverConfig(final short value, final boolean expected)
|
||||
throws Exception {
|
||||
mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(value));
|
||||
assertDumpContains(getDump(),
|
||||
"sDataSaverEnabledMap: " + expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testDumpDataSaverConfig() throws Exception {
|
||||
doTestDumpDataSaverConfig(DATA_SAVER_DISABLED, false);
|
||||
doTestDumpDataSaverConfig(DATA_SAVER_ENABLED, true);
|
||||
doTestDumpDataSaverConfig((short) 2, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUids() throws ErrnoException {
|
||||
final int uid0 = TEST_UIDS[0];
|
||||
|
@ -1183,4 +1204,23 @@ public final class BpfNetMapsTest {
|
|||
assertThrows(expected,
|
||||
() -> mBpfNetMaps.getUidsWithAllowRuleOnAllowListChain(FIREWALL_CHAIN_OEM_DENY_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreAfter(Build.VERSION_CODES.S_V2)
|
||||
public void testSetDataSaverEnabledBeforeT() {
|
||||
for (boolean enable : new boolean[] {true, false}) {
|
||||
assertThrows(UnsupportedOperationException.class,
|
||||
() -> mBpfNetMaps.setDataSaverEnabled(enable));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testSetDataSaverEnabled() throws Exception {
|
||||
for (boolean enable : new boolean[] {true, false}) {
|
||||
mBpfNetMaps.setDataSaverEnabled(enable);
|
||||
assertEquals(enable ? DATA_SAVER_ENABLED : DATA_SAVER_DISABLED,
|
||||
mDataSaverEnabledMap.getValue(DATA_SAVER_ENABLED_KEY).val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue