Merge changes from topic "sp31" am: a6cb322d00

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1626082

Change-Id: I906d49ba06054f124e60f39ed40c40472e28546d
This commit is contained in:
Junyu Lai
2021-06-24 10:41:43 +00:00
committed by Automerger Merge Worker
2 changed files with 168 additions and 25 deletions

View File

@@ -26,6 +26,8 @@ import static android.net.NetworkStats.UID_TETHERING;
import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_1;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE; import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
@@ -280,6 +282,18 @@ public class OffloadController {
} }
} }
@Override
public void onWarningReached() {
if (!started()) return;
mLog.log("onWarningReached");
updateStatsForCurrentUpstream();
if (mStatsProvider != null) {
mStatsProvider.pushTetherStats();
mStatsProvider.notifyWarningReached();
}
}
@Override @Override
public void onNatTimeoutUpdate(int proto, public void onNatTimeoutUpdate(int proto,
String srcAddr, int srcPort, String srcAddr, int srcPort,
@@ -417,7 +431,11 @@ public class OffloadController {
@Override @Override
public void onSetAlert(long quotaBytes) { public void onSetAlert(long quotaBytes) {
// TODO: Ask offload HAL to notify alert without stopping traffic. // Ignore set alert calls from HAL V1.1 since the hardware supports set warning now.
// Thus, the software polling mechanism is not needed.
if (!useStatsPolling()) {
return;
}
// Post it to handler thread since it access remaining quota bytes. // Post it to handler thread since it access remaining quota bytes.
mHandler.post(() -> { mHandler.post(() -> {
updateAlertQuota(quotaBytes); updateAlertQuota(quotaBytes);
@@ -502,12 +520,17 @@ public class OffloadController {
private boolean isPollingStatsNeeded() { private boolean isPollingStatsNeeded() {
return started() && mRemainingAlertQuota > 0 return started() && mRemainingAlertQuota > 0
&& useStatsPolling()
&& !TextUtils.isEmpty(currentUpstreamInterface()) && !TextUtils.isEmpty(currentUpstreamInterface())
&& mDeps.getTetherConfig() != null && mDeps.getTetherConfig() != null
&& mDeps.getTetherConfig().getOffloadPollInterval() && mDeps.getTetherConfig().getOffloadPollInterval()
>= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; >= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
} }
private boolean useStatsPolling() {
return mControlHalVersion == OFFLOAD_HAL_VERSION_1_0;
}
private boolean maybeUpdateDataWarningAndLimit(String iface) { private boolean maybeUpdateDataWarningAndLimit(String iface) {
// setDataLimit or setDataWarningAndLimit may only be called while offload is occurring // setDataLimit or setDataWarningAndLimit may only be called while offload is occurring
// on this upstream. // on this upstream.
@@ -516,7 +539,13 @@ public class OffloadController {
} }
final InterfaceQuota quota = mInterfaceQuotas.getOrDefault(iface, InterfaceQuota.MAX_VALUE); final InterfaceQuota quota = mInterfaceQuotas.getOrDefault(iface, InterfaceQuota.MAX_VALUE);
return mHwInterface.setDataLimit(iface, quota.limitBytes); final boolean ret;
if (mControlHalVersion >= OFFLOAD_HAL_VERSION_1_1) {
ret = mHwInterface.setDataWarningAndLimit(iface, quota.warningBytes, quota.limitBytes);
} else {
ret = mHwInterface.setDataLimit(iface, quota.limitBytes);
}
return ret;
} }
private void updateStatsForCurrentUpstream() { private void updateStatsForCurrentUpstream() {

View File

@@ -149,6 +149,7 @@ public class OffloadControllerTest {
when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true); when(mHardware.setUpstreamParameters(anyString(), any(), any(), any())).thenReturn(true);
when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats()); when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true);
} }
private void enableOffload() { private void enableOffload() {
@@ -503,80 +504,166 @@ public class OffloadControllerTest {
} }
/** /**
* Test OffloadController that uses V1.0 HAL setDataLimit with NetworkStatsProvider#onSetLimit * Test OffloadController with different combinations of HAL and framework versions can set
* which is called by R framework. * data warning and/or limit correctly.
*/ */
@Test @Test
public void testSetDataLimit() throws Exception { public void testSetDataWarningAndLimit() throws Exception {
// Verify the OffloadController is called by R framework, where the framework doesn't send
// warning.
checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_1_0);
checkSetDataWarningAndLimit(false, OFFLOAD_HAL_VERSION_1_1);
// Verify the OffloadController is called by S+ framework, where the framework sends
// warning along with limit.
checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_0);
checkSetDataWarningAndLimit(true, OFFLOAD_HAL_VERSION_1_1);
}
private void checkSetDataWarningAndLimit(boolean isProviderSetWarning, int controlVersion)
throws Exception {
enableOffload(); enableOffload();
final OffloadController offload = final OffloadController offload =
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); startOffloadController(controlVersion, true /*expectStart*/);
final String ethernetIface = "eth1"; final String ethernetIface = "eth1";
final String mobileIface = "rmnet_data0"; final String mobileIface = "rmnet_data0";
final long ethernetLimit = 12345; final long ethernetLimit = 12345;
final long mobileWarning = 123456;
final long mobileLimit = 12345678; final long mobileLimit = 12345678;
final LinkProperties lp = new LinkProperties(); final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(ethernetIface); lp.setInterfaceName(ethernetIface);
offload.setUpstreamLinkProperties(lp);
final InOrder inOrder = inOrder(mHardware); final InOrder inOrder = inOrder(mHardware);
when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); when(mHardware.setUpstreamParameters(
any(), any(), any(), any())).thenReturn(true);
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(true);
offload.setUpstreamLinkProperties(lp);
// Applying an interface sends the initial quota to the hardware.
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE,
Long.MAX_VALUE);
} else {
inOrder.verify(mHardware).setDataLimit(ethernetIface, Long.MAX_VALUE);
}
inOrder.verifyNoMoreInteractions();
// Verify that set to unlimited again won't cause duplicated calls to the hardware.
if (isProviderSetWarning) {
mTetherStatsProvider.onSetWarningAndLimit(ethernetIface,
NetworkStatsProvider.QUOTA_UNLIMITED, NetworkStatsProvider.QUOTA_UNLIMITED);
} else {
mTetherStatsProvider.onSetLimit(ethernetIface, NetworkStatsProvider.QUOTA_UNLIMITED);
}
waitForIdle();
inOrder.verifyNoMoreInteractions();
// Applying an interface quota to the current upstream immediately sends it to the hardware. // Applying an interface quota to the current upstream immediately sends it to the hardware.
mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit); if (isProviderSetWarning) {
mTetherStatsProvider.onSetWarningAndLimit(ethernetIface,
NetworkStatsProvider.QUOTA_UNLIMITED, ethernetLimit);
} else {
mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit);
}
waitForIdle(); waitForIdle();
inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
inOrder.verify(mHardware).setDataWarningAndLimit(ethernetIface, Long.MAX_VALUE,
ethernetLimit);
} else {
inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit);
}
inOrder.verifyNoMoreInteractions(); inOrder.verifyNoMoreInteractions();
// Applying an interface quota to another upstream does not take any immediate action. // Applying an interface quota to another upstream does not take any immediate action.
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); if (isProviderSetWarning) {
mTetherStatsProvider.onSetWarningAndLimit(mobileIface, mobileWarning, mobileLimit);
} else {
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit);
}
waitForIdle(); waitForIdle();
inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(),
anyLong());
} else {
inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
}
// Switching to that upstream causes the quota to be applied if the parameters were applied // Switching to that upstream causes the quota to be applied if the parameters were applied
// correctly. // correctly.
lp.setInterfaceName(mobileIface); lp.setInterfaceName(mobileIface);
offload.setUpstreamLinkProperties(lp); offload.setUpstreamLinkProperties(lp);
waitForIdle(); waitForIdle();
inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit); if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface,
isProviderSetWarning ? mobileWarning : Long.MAX_VALUE,
mobileLimit);
} else {
inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit);
}
// Setting a limit of NetworkStatsProvider.QUOTA_UNLIMITED causes the limit to be set // Setting a limit of NetworkStatsProvider.QUOTA_UNLIMITED causes the limit to be set
// to Long.MAX_VALUE. // to Long.MAX_VALUE.
mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED); if (isProviderSetWarning) {
mTetherStatsProvider.onSetWarningAndLimit(mobileIface,
NetworkStatsProvider.QUOTA_UNLIMITED, NetworkStatsProvider.QUOTA_UNLIMITED);
} else {
mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED);
}
waitForIdle(); waitForIdle();
inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
inOrder.verify(mHardware).setDataWarningAndLimit(mobileIface, Long.MAX_VALUE,
Long.MAX_VALUE);
} else {
inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE);
}
// If setting upstream parameters fails, then the data limit is not set. // If setting upstream parameters fails, then the data warning and limit is not set.
when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false);
lp.setInterfaceName(ethernetIface); lp.setInterfaceName(ethernetIface);
offload.setUpstreamLinkProperties(lp); offload.setUpstreamLinkProperties(lp);
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); if (isProviderSetWarning) {
mTetherStatsProvider.onSetWarningAndLimit(mobileIface, mobileWarning, mobileLimit);
} else {
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit);
}
waitForIdle(); waitForIdle();
inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
inOrder.verify(mHardware, never()).setDataWarningAndLimit(anyString(), anyLong(),
anyLong());
// If setting the data limit fails while changing upstreams, offload is stopped. // If setting the data warning and/or limit fails while changing upstreams, offload is
// stopped.
when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false);
when(mHardware.setDataWarningAndLimit(anyString(), anyLong(), anyLong())).thenReturn(false);
lp.setInterfaceName(mobileIface); lp.setInterfaceName(mobileIface);
offload.setUpstreamLinkProperties(lp); offload.setUpstreamLinkProperties(lp);
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); if (isProviderSetWarning) {
mTetherStatsProvider.onSetWarningAndLimit(mobileIface, mobileWarning, mobileLimit);
} else {
mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit);
}
waitForIdle(); waitForIdle();
inOrder.verify(mHardware).getForwardedStats(ethernetIface); inOrder.verify(mHardware).getForwardedStats(ethernetIface);
inOrder.verify(mHardware).stopOffloadControl(); inOrder.verify(mHardware).stopOffloadControl();
} }
@Test @Test
public void testDataLimitCallback() throws Exception { public void testDataWarningAndLimitCallback() throws Exception {
enableOffload(); enableOffload();
final OffloadController offload = startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
callback.onStoppedLimitReached(); callback.onStoppedLimitReached();
mTetherStatsProviderCb.expectNotifyStatsUpdated(); mTetherStatsProviderCb.expectNotifyStatsUpdated();
mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
startOffloadController(OFFLOAD_HAL_VERSION_1_1, true /*expectStart*/);
callback = mControlCallbackCaptor.getValue();
callback.onWarningReached();
mTetherStatsProviderCb.expectNotifyStatsUpdated();
mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
} }
@Test @Test
@@ -764,9 +851,7 @@ public class OffloadControllerTest {
// Initialize with fake eth upstream. // Initialize with fake eth upstream.
final String ethernetIface = "eth1"; final String ethernetIface = "eth1";
InOrder inOrder = inOrder(mHardware); InOrder inOrder = inOrder(mHardware);
final LinkProperties lp = new LinkProperties(); offload.setUpstreamLinkProperties(makeEthernetLinkProperties());
lp.setInterfaceName(ethernetIface);
offload.setUpstreamLinkProperties(lp);
// Previous upstream was null, so no stats are fetched. // Previous upstream was null, so no stats are fetched.
inOrder.verify(mHardware, never()).getForwardedStats(any()); inOrder.verify(mHardware, never()).getForwardedStats(any());
@@ -799,4 +884,33 @@ public class OffloadControllerTest {
mTetherStatsProviderCb.assertNoCallback(); mTetherStatsProviderCb.assertNoCallback();
verify(mHardware, never()).getForwardedStats(any()); verify(mHardware, never()).getForwardedStats(any());
} }
private static LinkProperties makeEthernetLinkProperties() {
final String ethernetIface = "eth1";
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(ethernetIface);
return lp;
}
private void checkSoftwarePollingUsed(int controlVersion) throws Exception {
enableOffload();
setOffloadPollInterval(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
OffloadController offload =
startOffloadController(controlVersion, true /*expectStart*/);
offload.setUpstreamLinkProperties(makeEthernetLinkProperties());
mTetherStatsProvider.onSetAlert(0);
waitForIdle();
if (controlVersion >= OFFLOAD_HAL_VERSION_1_1) {
mTetherStatsProviderCb.assertNoCallback();
} else {
mTetherStatsProviderCb.expectNotifyAlertReached();
}
verify(mHardware, never()).getForwardedStats(any());
}
@Test
public void testSoftwarePollingUsed() throws Exception {
checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_1_0);
checkSoftwarePollingUsed(OFFLOAD_HAL_VERSION_1_1);
}
} }