From 8bf2e7e05b11e5cfe708feebb60fe91c4bf8ac1f Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Thu, 2 Apr 2020 18:47:19 +0800 Subject: [PATCH] Add tether BPF offload config to device config and resource The tether bpf offload can be enabled by resource config and device config. The device config has higher priority and it could override this config which is set by resource config. Bug: 149997301 Test: -build, flash, boot -atest TetheringConfigurationTest Change-Id: I9c26852d2c926786e141ece6da53df3801c049b2 --- Tethering/res/values/config.xml | 6 +++ Tethering/res/values/overlayable.xml | 5 ++ .../tethering/TetheringConfiguration.java | 42 +++++++++++++++-- .../tethering/TetheringConfigurationTest.java | 46 +++++++++++++++++++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml index c999221963..0ea459a6cf 100644 --- a/Tethering/res/values/config.xml +++ b/Tethering/res/values/config.xml @@ -55,6 +55,12 @@ "bt-pan" + + true + false diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml index 4c78a74d53..288dd5ddf3 100644 --- a/Tethering/res/values/overlayable.xml +++ b/Tethering/res/values/overlayable.xml @@ -23,6 +23,11 @@ + + diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 9d4e747327..91a6e29a05 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -72,6 +72,12 @@ public class TetheringConfiguration { private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"}; + /** + * Override enabling BPF offload configuration for tethering. + */ + public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD = + "override_tether_enable_bpf_offload"; + /** * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. */ @@ -95,6 +101,8 @@ public class TetheringConfiguration { public final String[] legacyDhcpRanges; public final String[] defaultIPv4DNS; public final boolean enableLegacyDhcpServer; + // TODO: Add to TetheringConfigurationParcel if required. + public final boolean enableBpfOffload; public final String[] provisioningApp; public final String provisioningAppNoUi; @@ -124,11 +132,12 @@ public class TetheringConfiguration { isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean( - res, R.bool.config_tether_upstream_automatic); + res, R.bool.config_tether_upstream_automatic, false /** default value */); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); + enableBpfOffload = getEnableBpfOffload(res); enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); @@ -208,6 +217,9 @@ public class TetheringConfiguration { pw.print("provisioningAppNoUi: "); pw.println(provisioningAppNoUi); + pw.print("enableBpfOffload: "); + pw.println(enableBpfOffload); + pw.print("enableLegacyDhcpServer: "); pw.println(enableLegacyDhcpServer); } @@ -228,6 +240,7 @@ public class TetheringConfiguration { toIntArray(preferredUpstreamIfaceTypes))); sj.add(String.format("provisioningApp:%s", makeString(provisioningApp))); sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi)); + sj.add(String.format("enableBpfOffload:%s", enableBpfOffload)); sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer)); return String.format("TetheringConfiguration{%s}", sj.toString()); } @@ -332,11 +345,11 @@ public class TetheringConfiguration { } } - private static boolean getResourceBoolean(Resources res, int resId) { + private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) { try { return res.getBoolean(resId); } catch (Resources.NotFoundException e404) { - return false; + return defaultValue; } } @@ -357,8 +370,29 @@ public class TetheringConfiguration { } } + private boolean getEnableBpfOffload(final Resources res) { + // Get BPF offload config + // Priority 1: Device config + // Priority 2: Resource config + // Priority 3: Default value + final boolean resourceValue = getResourceBoolean( + res, R.bool.config_tether_enable_bpf_offload, true /** default value */); + + // Due to the limitation of static mock for testing, using #getProperty directly instead + // of getDeviceConfigBoolean. getDeviceConfigBoolean is not invoked because it uses + // #getBoolean to get the boolean device config. The test can't know that the returned + // boolean value comes from device config or default value (because of null property + // string). Because the test would like to verify null property boolean string case, + // use DeviceConfig.getProperty here. See also the test case testBpfOffload{*} in + // TetheringConfigurationTest.java. + final String value = DeviceConfig.getProperty( + NAMESPACE_CONNECTIVITY, OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD); + return (value != null) ? Boolean.parseBoolean(value) : resourceValue; + } + private boolean getEnableLegacyDhcpServer(final Resources res) { - return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server) + return getResourceBoolean( + res, R.bool.config_tether_enable_legacy_dhcp_server, false /** default value */) || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index e8ba5b8168..fbfa871f76 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -127,6 +127,8 @@ public class TetheringConfigurationTest { .thenReturn(new String[0]); when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( false); + initializeBpfOffloadConfiguration(true, null /* unset */); + mHasTelephonyManager = true; mMockContext = new MockContext(mContext); mEnableLegacyDhcpServer = false; @@ -278,6 +280,50 @@ public class TetheringConfigurationTest { assertFalse(upstreamIterator.hasNext()); } + private void initializeBpfOffloadConfiguration( + final boolean fromRes, final String fromDevConfig) { + when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes); + doReturn(fromDevConfig).when( + () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), + eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD))); + } + + @Test + public void testBpfOffloadEnabledByResource() { + initializeBpfOffloadConfiguration(true, null /* unset */); + final TetheringConfiguration enableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByRes.enableBpfOffload); + } + + @Test + public void testBpfOffloadEnabledByDeviceConfigOverride() { + for (boolean res : new boolean[]{true, false}) { + initializeBpfOffloadConfiguration(res, "true"); + final TetheringConfiguration enableByDevConOverride = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertTrue(enableByDevConOverride.enableBpfOffload); + } + } + + @Test + public void testBpfOffloadDisabledByResource() { + initializeBpfOffloadConfiguration(false, null /* unset */); + final TetheringConfiguration disableByRes = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(disableByRes.enableBpfOffload); + } + + @Test + public void testBpfOffloadDisabledByDeviceConfigOverride() { + for (boolean res : new boolean[]{true, false}) { + initializeBpfOffloadConfiguration(res, "false"); + final TetheringConfiguration disableByDevConOverride = + new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(disableByDevConOverride.enableBpfOffload); + } + } + @Test public void testNewDhcpServerDisabled() { when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(