[SP34] Adapt onSetWarningAndLimit am: da52dab266

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

Change-Id: Id0d1dbe3276b4c16f684109fa55ffe5c5343ed42
This commit is contained in:
junyulai
2021-06-24 10:41:41 +00:00
committed by Automerger Merge Worker
2 changed files with 63 additions and 20 deletions

View File

@@ -114,11 +114,42 @@ public class OffloadController {
private ConcurrentHashMap<String, ForwardedStats> mForwardedStats = private ConcurrentHashMap<String, ForwardedStats> mForwardedStats =
new ConcurrentHashMap<>(16, 0.75F, 1); new ConcurrentHashMap<>(16, 0.75F, 1);
private static class InterfaceQuota {
public final long warningBytes;
public final long limitBytes;
public static InterfaceQuota MAX_VALUE = new InterfaceQuota(Long.MAX_VALUE, Long.MAX_VALUE);
InterfaceQuota(long warningBytes, long limitBytes) {
this.warningBytes = warningBytes;
this.limitBytes = limitBytes;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof InterfaceQuota)) return false;
InterfaceQuota that = (InterfaceQuota) o;
return warningBytes == that.warningBytes
&& limitBytes == that.limitBytes;
}
@Override
public int hashCode() {
return (int) (warningBytes * 3 + limitBytes * 5);
}
@Override
public String toString() {
return "InterfaceQuota{" + "warning=" + warningBytes + ", limit=" + limitBytes + '}';
}
}
// Maps upstream interface names to interface quotas. // Maps upstream interface names to interface quotas.
// Always contains the latest value received from the framework for each interface, regardless // Always contains the latest value received from the framework for each interface, regardless
// of whether offload is currently running (or is even supported) on that interface. Only // of whether offload is currently running (or is even supported) on that interface. Only
// includes upstream interfaces that have a quota set. // includes upstream interfaces that have a quota set.
private HashMap<String, Long> mInterfaceQuotas = new HashMap<>(); private HashMap<String, InterfaceQuota> mInterfaceQuotas = new HashMap<>();
// Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert
// quota is interface independent and global for tether offload. Note that this is only // quota is interface independent and global for tether offload. Note that this is only
@@ -263,7 +294,8 @@ public class OffloadController {
mLog.i("tethering offload control not supported"); mLog.i("tethering offload control not supported");
stop(); stop();
} else { } else {
mLog.log("tethering offload started"); mLog.log("tethering offload started, version: "
+ OffloadHardwareInterface.halVerToString(mControlHalVersion));
mNatUpdateCallbacksReceived = 0; mNatUpdateCallbacksReceived = 0;
mNatUpdateNetlinkErrors = 0; mNatUpdateNetlinkErrors = 0;
maybeSchedulePollingStats(); maybeSchedulePollingStats();
@@ -322,24 +354,35 @@ public class OffloadController {
@Override @Override
public void onSetLimit(String iface, long quotaBytes) { public void onSetLimit(String iface, long quotaBytes) {
onSetWarningAndLimit(iface, QUOTA_UNLIMITED, quotaBytes);
}
@Override
public void onSetWarningAndLimit(@NonNull String iface,
long warningBytes, long limitBytes) {
// Listen for all iface is necessary since upstream might be changed after limit // Listen for all iface is necessary since upstream might be changed after limit
// is set. // is set.
mHandler.post(() -> { mHandler.post(() -> {
final Long curIfaceQuota = mInterfaceQuotas.get(iface); final InterfaceQuota curIfaceQuota = mInterfaceQuotas.get(iface);
final InterfaceQuota newIfaceQuota = new InterfaceQuota(
warningBytes == QUOTA_UNLIMITED ? Long.MAX_VALUE : warningBytes,
limitBytes == QUOTA_UNLIMITED ? Long.MAX_VALUE : limitBytes);
// If the quota is set to unlimited, the value set to HAL is Long.MAX_VALUE, // If the quota is set to unlimited, the value set to HAL is Long.MAX_VALUE,
// which is ~8.4 x 10^6 TiB, no one can actually reach it. Thus, it is not // which is ~8.4 x 10^6 TiB, no one can actually reach it. Thus, it is not
// useful to set it multiple times. // useful to set it multiple times.
// Otherwise, the quota needs to be updated to tell HAL to re-count from now even // Otherwise, the quota needs to be updated to tell HAL to re-count from now even
// if the quota is the same as the existing one. // if the quota is the same as the existing one.
if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return; if (null == curIfaceQuota && InterfaceQuota.MAX_VALUE.equals(newIfaceQuota)) {
return;
}
if (quotaBytes == QUOTA_UNLIMITED) { if (InterfaceQuota.MAX_VALUE.equals(newIfaceQuota)) {
mInterfaceQuotas.remove(iface); mInterfaceQuotas.remove(iface);
} else { } else {
mInterfaceQuotas.put(iface, quotaBytes); mInterfaceQuotas.put(iface, newIfaceQuota);
} }
maybeUpdateDataLimit(iface); maybeUpdateDataWarningAndLimit(iface);
}); });
} }
@@ -465,18 +508,15 @@ public class OffloadController {
>= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; >= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
} }
private boolean maybeUpdateDataLimit(String iface) { private boolean maybeUpdateDataWarningAndLimit(String iface) {
// setDataLimit may only be called while offload is occurring on this upstream. // setDataLimit or setDataWarningAndLimit may only be called while offload is occurring
// on this upstream.
if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) { if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) {
return true; return true;
} }
Long limit = mInterfaceQuotas.get(iface); final InterfaceQuota quota = mInterfaceQuotas.getOrDefault(iface, InterfaceQuota.MAX_VALUE);
if (limit == null) { return mHwInterface.setDataLimit(iface, quota.limitBytes);
limit = Long.MAX_VALUE;
}
return mHwInterface.setDataLimit(iface, limit);
} }
private void updateStatsForCurrentUpstream() { private void updateStatsForCurrentUpstream() {
@@ -630,7 +670,7 @@ public class OffloadController {
maybeUpdateStats(prevUpstream); maybeUpdateStats(prevUpstream);
// Data limits can only be set once offload is running on the upstream. // Data limits can only be set once offload is running on the upstream.
success = maybeUpdateDataLimit(iface); success = maybeUpdateDataWarningAndLimit(iface);
if (!success) { if (!success) {
// If we failed to set a data limit, don't use this upstream, because we don't want to // If we failed to set a data limit, don't use this upstream, because we don't want to
// blow through the data limit that we were told to apply. // blow through the data limit that we were told to apply.

View File

@@ -58,7 +58,6 @@ import android.annotation.NonNull;
import android.app.usage.NetworkStatsManager; import android.app.usage.NetworkStatsManager;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.net.ITetheringStatsProvider;
import android.net.IpPrefix; import android.net.IpPrefix;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -503,8 +502,12 @@ public class OffloadControllerTest {
expectedUidStatsDiff); expectedUidStatsDiff);
} }
/**
* Test OffloadController that uses V1.0 HAL setDataLimit with NetworkStatsProvider#onSetLimit
* which is called by R framework.
*/
@Test @Test
public void testSetInterfaceQuota() throws Exception { public void testSetDataLimit() throws Exception {
enableOffload(); enableOffload();
final OffloadController offload = final OffloadController offload =
startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/); startOffloadController(OFFLOAD_HAL_VERSION_1_0, true /*expectStart*/);
@@ -540,9 +543,9 @@ public class OffloadControllerTest {
waitForIdle(); waitForIdle();
inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit); inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit);
// Setting a limit of ITetheringStatsProvider.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, ITetheringStatsProvider.QUOTA_UNLIMITED); mTetherStatsProvider.onSetLimit(mobileIface, NetworkStatsProvider.QUOTA_UNLIMITED);
waitForIdle(); waitForIdle();
inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE);