Merge changes from topic "sp31"
* changes: [SP35] Pass data warning to tethering offload [SP34] Adapt onSetWarningAndLimit [SP33] Adapt ITetheringOffloadCallback V1.1 Address comments on ag/14486203
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
@@ -114,11 +116,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
|
||||||
@@ -249,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,
|
||||||
@@ -263,7 +308,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 +368,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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,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);
|
||||||
@@ -459,24 +520,32 @@ 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 maybeUpdateDataLimit(String iface) {
|
private boolean useStatsPolling() {
|
||||||
// setDataLimit may only be called while offload is occurring on this upstream.
|
return mControlHalVersion == OFFLOAD_HAL_VERSION_1_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean maybeUpdateDataWarningAndLimit(String iface) {
|
||||||
|
// 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) {
|
final boolean ret;
|
||||||
limit = Long.MAX_VALUE;
|
if (mControlHalVersion >= OFFLOAD_HAL_VERSION_1_1) {
|
||||||
|
ret = mHwInterface.setDataWarningAndLimit(iface, quota.warningBytes, quota.limitBytes);
|
||||||
|
} else {
|
||||||
|
ret = mHwInterface.setDataLimit(iface, quota.limitBytes);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
return mHwInterface.setDataLimit(iface, limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStatsForCurrentUpstream() {
|
private void updateStatsForCurrentUpstream() {
|
||||||
@@ -630,7 +699,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.
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ import android.annotation.IntDef;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
||||||
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
||||||
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
||||||
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
||||||
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
||||||
|
import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback;
|
||||||
import android.net.netlink.NetlinkSocket;
|
import android.net.netlink.NetlinkSocket;
|
||||||
import android.net.netlink.StructNfGenMsg;
|
import android.net.netlink.StructNfGenMsg;
|
||||||
import android.net.netlink.StructNlMsgHdr;
|
import android.net.netlink.StructNlMsgHdr;
|
||||||
@@ -39,6 +39,7 @@ import android.os.RemoteException;
|
|||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -140,6 +141,8 @@ public class OffloadHardwareInterface {
|
|||||||
public void onSupportAvailable() {}
|
public void onSupportAvailable() {}
|
||||||
/** Offload stopped because of usage limit reached. */
|
/** Offload stopped because of usage limit reached. */
|
||||||
public void onStoppedLimitReached() {}
|
public void onStoppedLimitReached() {}
|
||||||
|
/** Indicate that data warning quota is reached. */
|
||||||
|
public void onWarningReached() {}
|
||||||
|
|
||||||
/** Indicate to update NAT timeout. */
|
/** Indicate to update NAT timeout. */
|
||||||
public void onNatTimeoutUpdate(int proto,
|
public void onNatTimeoutUpdate(int proto,
|
||||||
@@ -381,7 +384,8 @@ public class OffloadHardwareInterface {
|
|||||||
(controlCb == null) ? "null"
|
(controlCb == null) ? "null"
|
||||||
: "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
|
: "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
|
||||||
|
|
||||||
mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
|
mTetheringOffloadCallback = new TetheringOffloadCallback(
|
||||||
|
mHandler, mControlCallback, mLog, mOffloadControlVersion);
|
||||||
final CbResults results = new CbResults();
|
final CbResults results = new CbResults();
|
||||||
try {
|
try {
|
||||||
mOffloadControl.initOffload(
|
mOffloadControl.initOffload(
|
||||||
@@ -480,6 +484,33 @@ public class OffloadHardwareInterface {
|
|||||||
return results.mSuccess;
|
return results.mSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set data warning and limit value to offload management process. */
|
||||||
|
public boolean setDataWarningAndLimit(String iface, long warning, long limit) {
|
||||||
|
if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"setDataWarningAndLimit is not supported below HAL V1.1");
|
||||||
|
}
|
||||||
|
final String logmsg =
|
||||||
|
String.format("setDataWarningAndLimit(%s, %d, %d)", iface, warning, limit);
|
||||||
|
|
||||||
|
final CbResults results = new CbResults();
|
||||||
|
try {
|
||||||
|
((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mOffloadControl)
|
||||||
|
.setDataWarningAndLimit(
|
||||||
|
iface, warning, limit,
|
||||||
|
(boolean success, String errMsg) -> {
|
||||||
|
results.mSuccess = success;
|
||||||
|
results.mErrMsg = errMsg;
|
||||||
|
});
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
record(logmsg, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record(logmsg, results);
|
||||||
|
return results.mSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/** Set upstream parameters to offload management process. */
|
/** Set upstream parameters to offload management process. */
|
||||||
public boolean setUpstreamParameters(
|
public boolean setUpstreamParameters(
|
||||||
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
|
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
|
||||||
@@ -565,35 +596,64 @@ public class OffloadHardwareInterface {
|
|||||||
public final Handler handler;
|
public final Handler handler;
|
||||||
public final ControlCallback controlCb;
|
public final ControlCallback controlCb;
|
||||||
public final SharedLog log;
|
public final SharedLog log;
|
||||||
|
private final int mOffloadControlVersion;
|
||||||
|
|
||||||
TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
|
TetheringOffloadCallback(
|
||||||
|
Handler h, ControlCallback cb, SharedLog sharedLog, int offloadControlVersion) {
|
||||||
handler = h;
|
handler = h;
|
||||||
controlCb = cb;
|
controlCb = cb;
|
||||||
log = sharedLog;
|
log = sharedLog;
|
||||||
|
this.mOffloadControlVersion = offloadControlVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleOnEvent(int event) {
|
||||||
|
switch (event) {
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STARTED:
|
||||||
|
controlCb.onStarted();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
|
||||||
|
controlCb.onStoppedError();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
|
||||||
|
controlCb.onStoppedUnsupported();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
|
||||||
|
controlCb.onSupportAvailable();
|
||||||
|
break;
|
||||||
|
case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
|
||||||
|
controlCb.onStoppedLimitReached();
|
||||||
|
break;
|
||||||
|
case android.hardware.tetheroffload.control
|
||||||
|
.V1_1.OffloadCallbackEvent.OFFLOAD_WARNING_REACHED:
|
||||||
|
controlCb.onWarningReached();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.e("Unsupported OffloadCallbackEvent: " + event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(int event) {
|
public void onEvent(int event) {
|
||||||
|
// The implementation should never call onEvent()) if the event is already reported
|
||||||
|
// through newer callback.
|
||||||
|
if (mOffloadControlVersion > OFFLOAD_HAL_VERSION_1_0) {
|
||||||
|
Log.wtf(TAG, "onEvent(" + event + ") fired on HAL "
|
||||||
|
+ halVerToString(mOffloadControlVersion));
|
||||||
|
}
|
||||||
handler.post(() -> {
|
handler.post(() -> {
|
||||||
switch (event) {
|
handleOnEvent(event);
|
||||||
case OffloadCallbackEvent.OFFLOAD_STARTED:
|
});
|
||||||
controlCb.onStarted();
|
}
|
||||||
break;
|
|
||||||
case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
|
@Override
|
||||||
controlCb.onStoppedError();
|
public void onEvent_1_1(int event) {
|
||||||
break;
|
if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) {
|
||||||
case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
|
Log.wtf(TAG, "onEvent_1_1(" + event + ") fired on HAL "
|
||||||
controlCb.onStoppedUnsupported();
|
+ halVerToString(mOffloadControlVersion));
|
||||||
break;
|
return;
|
||||||
case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
|
}
|
||||||
controlCb.onSupportAvailable();
|
handler.post(() -> {
|
||||||
break;
|
handleOnEvent(event);
|
||||||
case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
|
|
||||||
controlCb.onStoppedLimitReached();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log.e("Unsupported OffloadCallbackEvent: " + event);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -150,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,77 +503,167 @@ public class OffloadControllerTest {
|
|||||||
expectedUidStatsDiff);
|
expectedUidStatsDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test OffloadController with different combinations of HAL and framework versions can set
|
||||||
|
* data warning and/or limit correctly.
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSetInterfaceQuota() 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 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);
|
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
|
||||||
@@ -761,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());
|
||||||
|
|
||||||
@@ -796,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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,22 +22,27 @@ import static android.system.OsConstants.AF_UNIX;
|
|||||||
import static android.system.OsConstants.SOCK_STREAM;
|
import static android.system.OsConstants.SOCK_STREAM;
|
||||||
|
|
||||||
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_1_0;
|
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 org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
|
||||||
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
|
||||||
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
|
|
||||||
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
|
||||||
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
|
||||||
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
|
import android.hardware.tetheroffload.control.V1_1.ITetheringOffloadCallback;
|
||||||
|
import android.hardware.tetheroffload.control.V1_1.OffloadCallbackEvent;
|
||||||
import android.net.netlink.StructNfGenMsg;
|
import android.net.netlink.StructNfGenMsg;
|
||||||
import android.net.netlink.StructNlMsgHdr;
|
import android.net.netlink.StructNlMsgHdr;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
@@ -56,6 +61,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@@ -76,7 +82,7 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
private OffloadHardwareInterface.ControlCallback mControlCallback;
|
private OffloadHardwareInterface.ControlCallback mControlCallback;
|
||||||
|
|
||||||
@Mock private IOffloadConfig mIOffloadConfig;
|
@Mock private IOffloadConfig mIOffloadConfig;
|
||||||
@Mock private IOffloadControl mIOffloadControl;
|
private IOffloadControl mIOffloadControl;
|
||||||
@Mock private NativeHandle mNativeHandle;
|
@Mock private NativeHandle mNativeHandle;
|
||||||
|
|
||||||
// Random values to test Netlink message.
|
// Random values to test Netlink message.
|
||||||
@@ -84,8 +90,10 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
private static final short TEST_FLAGS = 263;
|
private static final short TEST_FLAGS = 263;
|
||||||
|
|
||||||
class MyDependencies extends OffloadHardwareInterface.Dependencies {
|
class MyDependencies extends OffloadHardwareInterface.Dependencies {
|
||||||
MyDependencies(SharedLog log) {
|
private final int mMockControlVersion;
|
||||||
|
MyDependencies(SharedLog log, final int mockControlVersion) {
|
||||||
super(log);
|
super(log);
|
||||||
|
mMockControlVersion = mockControlVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -95,7 +103,19 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<IOffloadControl, Integer> getOffloadControl() {
|
public Pair<IOffloadControl, Integer> getOffloadControl() {
|
||||||
return new Pair<IOffloadControl, Integer>(mIOffloadControl, OFFLOAD_HAL_VERSION_1_0);
|
switch (mMockControlVersion) {
|
||||||
|
case OFFLOAD_HAL_VERSION_1_0:
|
||||||
|
mIOffloadControl = mock(IOffloadControl.class);
|
||||||
|
break;
|
||||||
|
case OFFLOAD_HAL_VERSION_1_1:
|
||||||
|
mIOffloadControl =
|
||||||
|
mock(android.hardware.tetheroffload.control.V1_1.IOffloadControl.class);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid offload control version "
|
||||||
|
+ mMockControlVersion);
|
||||||
|
}
|
||||||
|
return new Pair<IOffloadControl, Integer>(mIOffloadControl, mMockControlVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -107,14 +127,13 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
final SharedLog log = new SharedLog("test");
|
|
||||||
mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log,
|
|
||||||
new MyDependencies(log));
|
|
||||||
mControlCallback = spy(new OffloadHardwareInterface.ControlCallback());
|
mControlCallback = spy(new OffloadHardwareInterface.ControlCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Pass version to test version specific operations.
|
private void startOffloadHardwareInterface(int controlVersion) throws Exception {
|
||||||
private void startOffloadHardwareInterface() throws Exception {
|
final SharedLog log = new SharedLog("test");
|
||||||
|
mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log,
|
||||||
|
new MyDependencies(log, controlVersion));
|
||||||
mOffloadHw.initOffloadConfig();
|
mOffloadHw.initOffloadConfig();
|
||||||
mOffloadHw.initOffloadControl(mControlCallback);
|
mOffloadHw.initOffloadControl(mControlCallback);
|
||||||
final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor =
|
final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor =
|
||||||
@@ -125,7 +144,7 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetForwardedStats() throws Exception {
|
public void testGetForwardedStats() throws Exception {
|
||||||
startOffloadHardwareInterface();
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0);
|
final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0);
|
||||||
verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any());
|
verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any());
|
||||||
assertNotNull(stats);
|
assertNotNull(stats);
|
||||||
@@ -133,7 +152,7 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetLocalPrefixes() throws Exception {
|
public void testSetLocalPrefixes() throws Exception {
|
||||||
startOffloadHardwareInterface();
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
final ArrayList<String> localPrefixes = new ArrayList<>();
|
final ArrayList<String> localPrefixes = new ArrayList<>();
|
||||||
localPrefixes.add("127.0.0.0/8");
|
localPrefixes.add("127.0.0.0/8");
|
||||||
localPrefixes.add("fe80::/64");
|
localPrefixes.add("fe80::/64");
|
||||||
@@ -143,15 +162,32 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetDataLimit() throws Exception {
|
public void testSetDataLimit() throws Exception {
|
||||||
startOffloadHardwareInterface();
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
final long limit = 12345;
|
final long limit = 12345;
|
||||||
mOffloadHw.setDataLimit(RMNET0, limit);
|
mOffloadHw.setDataLimit(RMNET0, limit);
|
||||||
verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any());
|
verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetDataWarningAndLimit() throws Exception {
|
||||||
|
// Verify V1.0 control HAL would reject the function call with exception.
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
|
final long warning = 12345;
|
||||||
|
final long limit = 67890;
|
||||||
|
assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit));
|
||||||
|
reset(mIOffloadControl);
|
||||||
|
|
||||||
|
// Verify V1.1 control HAL could receive this function call.
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_1);
|
||||||
|
mOffloadHw.setDataWarningAndLimit(RMNET0, warning, limit);
|
||||||
|
verify((android.hardware.tetheroffload.control.V1_1.IOffloadControl) mIOffloadControl)
|
||||||
|
.setDataWarningAndLimit(eq(RMNET0), eq(warning), eq(limit), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetUpstreamParameters() throws Exception {
|
public void testSetUpstreamParameters() throws Exception {
|
||||||
startOffloadHardwareInterface();
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
final String v4addr = "192.168.10.1";
|
final String v4addr = "192.168.10.1";
|
||||||
final String v4gateway = "192.168.10.255";
|
final String v4gateway = "192.168.10.255";
|
||||||
final ArrayList<String> v6gws = new ArrayList<>(0);
|
final ArrayList<String> v6gws = new ArrayList<>(0);
|
||||||
@@ -170,7 +206,7 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateDownstreamPrefix() throws Exception {
|
public void testUpdateDownstreamPrefix() throws Exception {
|
||||||
startOffloadHardwareInterface();
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
final String ifName = "wlan1";
|
final String ifName = "wlan1";
|
||||||
final String prefix = "192.168.43.0/24";
|
final String prefix = "192.168.43.0/24";
|
||||||
mOffloadHw.addDownstreamPrefix(ifName, prefix);
|
mOffloadHw.addDownstreamPrefix(ifName, prefix);
|
||||||
@@ -182,7 +218,7 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTetheringOffloadCallback() throws Exception {
|
public void testTetheringOffloadCallback() throws Exception {
|
||||||
startOffloadHardwareInterface();
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
|
|
||||||
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
|
mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
|
||||||
mTestLooper.dispatchAll();
|
mTestLooper.dispatchAll();
|
||||||
@@ -221,10 +257,26 @@ public final class OffloadHardwareInterfaceTest {
|
|||||||
eq(uint16(udpParams.src.port)),
|
eq(uint16(udpParams.src.port)),
|
||||||
eq(udpParams.dst.addr),
|
eq(udpParams.dst.addr),
|
||||||
eq(uint16(udpParams.dst.port)));
|
eq(uint16(udpParams.dst.port)));
|
||||||
|
reset(mControlCallback);
|
||||||
|
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_1);
|
||||||
|
|
||||||
|
// Verify the interface will process the events that comes from V1.1 HAL.
|
||||||
|
mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_STARTED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
final InOrder inOrder = inOrder(mControlCallback);
|
||||||
|
inOrder.verify(mControlCallback).onStarted();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
|
||||||
|
mTetheringOffloadCallback.onEvent_1_1(OffloadCallbackEvent.OFFLOAD_WARNING_REACHED);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
inOrder.verify(mControlCallback).onWarningReached();
|
||||||
|
inOrder.verifyNoMoreInteractions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSendIpv4NfGenMsg() throws Exception {
|
public void testSendIpv4NfGenMsg() throws Exception {
|
||||||
|
startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0);
|
||||||
FileDescriptor writeSocket = new FileDescriptor();
|
FileDescriptor writeSocket = new FileDescriptor();
|
||||||
FileDescriptor readSocket = new FileDescriptor();
|
FileDescriptor readSocket = new FileDescriptor();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -237,9 +237,9 @@ public class NetworkRanker {
|
|||||||
partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY),
|
partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY),
|
||||||
accepted, rejected);
|
accepted, rejected);
|
||||||
if (accepted.size() > 0) {
|
if (accepted.size() > 0) {
|
||||||
// Some networks are primary. For each transport, keep only the primary, but also
|
// Some networks are primary for their transport. For each transport, keep only the
|
||||||
// keep all networks for which there isn't a primary (which are now in the |rejected|
|
// primary, but also keep all networks for which there isn't a primary (which are now
|
||||||
// array).
|
// in the |rejected| array).
|
||||||
// So for each primary network, remove from |rejected| all networks with the same
|
// So for each primary network, remove from |rejected| all networks with the same
|
||||||
// transports as one of the primary networks. The remaining networks should be accepted.
|
// transports as one of the primary networks. The remaining networks should be accepted.
|
||||||
for (final T defaultSubNai : accepted) {
|
for (final T defaultSubNai : accepted) {
|
||||||
@@ -247,6 +247,8 @@ public class NetworkRanker {
|
|||||||
rejected.removeIf(
|
rejected.removeIf(
|
||||||
nai -> Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
|
nai -> Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
|
||||||
}
|
}
|
||||||
|
// Now the |rejected| list contains networks with transports for which there isn't
|
||||||
|
// a primary network. Add them back to the candidates.
|
||||||
accepted.addAll(rejected);
|
accepted.addAll(rejected);
|
||||||
candidates = new ArrayList<>(accepted);
|
candidates = new ArrayList<>(accepted);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user