diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index 7685847680..e3ac660910 100644 --- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -24,10 +24,10 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; 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.NetworkProtocol; 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.StructNfGenMsg; import android.net.netlink.StructNlMsgHdr; @@ -39,6 +39,7 @@ import android.os.RemoteException; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; @@ -140,6 +141,8 @@ public class OffloadHardwareInterface { public void onSupportAvailable() {} /** Offload stopped because of usage limit reached. */ public void onStoppedLimitReached() {} + /** Indicate that data warning quota is reached. */ + public void onWarningReached() {} /** Indicate to update NAT timeout. */ public void onNatTimeoutUpdate(int proto, @@ -381,7 +384,8 @@ public class OffloadHardwareInterface { (controlCb == null) ? "null" : "0x" + Integer.toHexString(System.identityHashCode(controlCb))); - mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog); + mTetheringOffloadCallback = new TetheringOffloadCallback( + mHandler, mControlCallback, mLog, mOffloadControlVersion); final CbResults results = new CbResults(); try { mOffloadControl.initOffload( @@ -480,6 +484,33 @@ public class OffloadHardwareInterface { 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. */ public boolean setUpstreamParameters( String iface, String v4addr, String v4gateway, ArrayList v6gws) { @@ -565,35 +596,64 @@ public class OffloadHardwareInterface { public final Handler handler; public final ControlCallback controlCb; 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; controlCb = cb; 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 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(() -> { - 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; - default: - log.e("Unsupported OffloadCallbackEvent: " + event); - } + handleOnEvent(event); + }); + } + + @Override + public void onEvent_1_1(int event) { + if (mOffloadControlVersion < OFFLOAD_HAL_VERSION_1_1) { + Log.wtf(TAG, "onEvent_1_1(" + event + ") fired on HAL " + + halVerToString(mOffloadControlVersion)); + return; + } + handler.post(() -> { + handleOnEvent(event); }); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java index f4194e5d77..a8b3b92de9 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java @@ -22,22 +22,27 @@ import static android.system.OsConstants.AF_UNIX; 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_1; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; 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.verify; import static org.mockito.Mockito.when; import android.hardware.tetheroffload.config.V1_0.IOffloadConfig; 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.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.StructNlMsgHdr; import android.net.util.SharedLog; @@ -56,6 +61,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -76,7 +82,7 @@ public final class OffloadHardwareInterfaceTest { private OffloadHardwareInterface.ControlCallback mControlCallback; @Mock private IOffloadConfig mIOffloadConfig; - @Mock private IOffloadControl mIOffloadControl; + private IOffloadControl mIOffloadControl; @Mock private NativeHandle mNativeHandle; // Random values to test Netlink message. @@ -84,8 +90,10 @@ public final class OffloadHardwareInterfaceTest { private static final short TEST_FLAGS = 263; class MyDependencies extends OffloadHardwareInterface.Dependencies { - MyDependencies(SharedLog log) { + private final int mMockControlVersion; + MyDependencies(SharedLog log, final int mockControlVersion) { super(log); + mMockControlVersion = mockControlVersion; } @Override @@ -95,7 +103,19 @@ public final class OffloadHardwareInterfaceTest { @Override public Pair getOffloadControl() { - return new Pair(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(mIOffloadControl, mMockControlVersion); } @Override @@ -107,14 +127,13 @@ public final class OffloadHardwareInterfaceTest { @Before public void setUp() { 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()); } - // TODO: Pass version to test version specific operations. - private void startOffloadHardwareInterface() throws Exception { + private void startOffloadHardwareInterface(int controlVersion) throws Exception { + final SharedLog log = new SharedLog("test"); + mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log, + new MyDependencies(log, controlVersion)); mOffloadHw.initOffloadConfig(); mOffloadHw.initOffloadControl(mControlCallback); final ArgumentCaptor mOffloadCallbackCaptor = @@ -125,7 +144,7 @@ public final class OffloadHardwareInterfaceTest { @Test public void testGetForwardedStats() throws Exception { - startOffloadHardwareInterface(); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0); verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any()); assertNotNull(stats); @@ -133,7 +152,7 @@ public final class OffloadHardwareInterfaceTest { @Test public void testSetLocalPrefixes() throws Exception { - startOffloadHardwareInterface(); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); final ArrayList localPrefixes = new ArrayList<>(); localPrefixes.add("127.0.0.0/8"); localPrefixes.add("fe80::/64"); @@ -143,15 +162,32 @@ public final class OffloadHardwareInterfaceTest { @Test public void testSetDataLimit() throws Exception { - startOffloadHardwareInterface(); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); final long limit = 12345; mOffloadHw.setDataLimit(RMNET0, limit); 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 public void testSetUpstreamParameters() throws Exception { - startOffloadHardwareInterface(); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); final String v4addr = "192.168.10.1"; final String v4gateway = "192.168.10.255"; final ArrayList v6gws = new ArrayList<>(0); @@ -170,7 +206,7 @@ public final class OffloadHardwareInterfaceTest { @Test public void testUpdateDownstreamPrefix() throws Exception { - startOffloadHardwareInterface(); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); final String ifName = "wlan1"; final String prefix = "192.168.43.0/24"; mOffloadHw.addDownstreamPrefix(ifName, prefix); @@ -182,7 +218,7 @@ public final class OffloadHardwareInterfaceTest { @Test public void testTetheringOffloadCallback() throws Exception { - startOffloadHardwareInterface(); + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); mTestLooper.dispatchAll(); @@ -221,10 +257,26 @@ public final class OffloadHardwareInterfaceTest { eq(uint16(udpParams.src.port)), eq(udpParams.dst.addr), 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 public void testSendIpv4NfGenMsg() throws Exception { + startOffloadHardwareInterface(OFFLOAD_HAL_VERSION_1_0); FileDescriptor writeSocket = new FileDescriptor(); FileDescriptor readSocket = new FileDescriptor(); try {