Loading packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +73 −51 Original line number Original line Diff line number Diff line Loading @@ -66,6 +66,7 @@ public class OffloadHardwareInterface { private final Handler mHandler; private final Handler mHandler; private final SharedLog mLog; private final SharedLog mLog; private final Dependencies mDeps; private IOffloadControl mOffloadControl; private IOffloadControl mOffloadControl; private TetheringOffloadCallback mTetheringOffloadCallback; private TetheringOffloadCallback mTetheringOffloadCallback; private ControlCallback mControlCallback; private ControlCallback mControlCallback; Loading Loading @@ -126,8 +127,76 @@ public class OffloadHardwareInterface { } } public OffloadHardwareInterface(Handler h, SharedLog log) { public OffloadHardwareInterface(Handler h, SharedLog log) { this(h, log, new Dependencies(log)); } OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) { mHandler = h; mHandler = h; mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mDeps = deps; } /** Capture OffloadHardwareInterface dependencies, for injection. */ static class Dependencies { private final SharedLog mLog; Dependencies(SharedLog log) { mLog = log; } public IOffloadConfig getOffloadConfig() { try { return IOffloadConfig.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("getIOffloadConfig error " + e); return null; } } public IOffloadControl getOffloadControl() { try { return IOffloadControl.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("tethering offload control not supported: " + e); return null; } } public NativeHandle createConntrackSocket(final int groups) { final FileDescriptor fd; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; } final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); try { Os.bind(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } try { Os.connect(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("connect to kernel fail for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } return new NativeHandle(fd, true); } } } /** Get default value indicating whether offload is supported. */ /** Get default value indicating whether offload is supported. */ Loading @@ -141,13 +210,7 @@ public class OffloadHardwareInterface { * share them with offload management process. * share them with offload management process. */ */ public boolean initOffloadConfig() { public boolean initOffloadConfig() { IOffloadConfig offloadConfig; final IOffloadConfig offloadConfig = mDeps.getOffloadConfig(); try { offloadConfig = IOffloadConfig.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("getIOffloadConfig error " + e); return false; } if (offloadConfig == null) { if (offloadConfig == null) { mLog.e("Could not find IOffloadConfig service"); mLog.e("Could not find IOffloadConfig service"); return false; return false; Loading @@ -159,11 +222,11 @@ public class OffloadHardwareInterface { // // // h2 provides a file descriptor bound to the following netlink groups // h2 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). final NativeHandle h1 = createConntrackSocket( final NativeHandle h1 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; if (h1 == null) return false; final NativeHandle h2 = createConntrackSocket( final NativeHandle h2 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); if (h2 == null) { if (h2 == null) { closeFdInNativeHandle(h1); closeFdInNativeHandle(h1); Loading Loading @@ -198,53 +261,12 @@ public class OffloadHardwareInterface { } } } } private NativeHandle createConntrackSocket(final int groups) { FileDescriptor fd; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; } final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); try { Os.bind(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } try { Os.connect(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("connect to kernel fail for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } return new NativeHandle(fd, true); } /** Initialize the tethering offload HAL. */ /** Initialize the tethering offload HAL. */ public boolean initOffloadControl(ControlCallback controlCb) { public boolean initOffloadControl(ControlCallback controlCb) { mControlCallback = controlCb; mControlCallback = controlCb; if (mOffloadControl == null) { if (mOffloadControl == null) { try { mOffloadControl = mDeps.getOffloadControl(); mOffloadControl = IOffloadControl.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("tethering offload control not supported: " + e); return false; } if (mOffloadControl == null) { if (mOffloadControl == null) { mLog.e("tethering IOffloadControl.getService() returned null"); mLog.e("tethering IOffloadControl.getService() returned null"); return false; return false; Loading packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java 0 → 100644 +215 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; 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.net.util.SharedLog; import android.os.Handler; import android.os.NativeHandle; import android.os.test.TestLooper; import android.system.OsConstants; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @SmallTest public final class OffloadHardwareInterfaceTest { private static final String RMNET0 = "test_rmnet_data0"; private final TestLooper mTestLooper = new TestLooper(); private OffloadHardwareInterface mOffloadHw; private ITetheringOffloadCallback mTetheringOffloadCallback; private OffloadHardwareInterface.ControlCallback mControlCallback; @Mock private IOffloadConfig mIOffloadConfig; @Mock private IOffloadControl mIOffloadControl; @Mock private NativeHandle mNativeHandle; class MyDependencies extends OffloadHardwareInterface.Dependencies { MyDependencies(SharedLog log) { super(log); } @Override public IOffloadConfig getOffloadConfig() { return mIOffloadConfig; } @Override public IOffloadControl getOffloadControl() { return mIOffloadControl; } @Override public NativeHandle createConntrackSocket(final int groups) { return mNativeHandle; } } @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()); } private void startOffloadHardwareInterface() throws Exception { mOffloadHw.initOffloadConfig(); mOffloadHw.initOffloadControl(mControlCallback); final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor = ArgumentCaptor.forClass(ITetheringOffloadCallback.class); verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any()); mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue(); } @Test public void testGetForwardedStats() throws Exception { startOffloadHardwareInterface(); final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0); verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any()); assertNotNull(stats); } @Test public void testSetLocalPrefixes() throws Exception { startOffloadHardwareInterface(); final ArrayList<String> localPrefixes = new ArrayList<>(); localPrefixes.add("127.0.0.0/8"); localPrefixes.add("fe80::/64"); mOffloadHw.setLocalPrefixes(localPrefixes); verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any()); } @Test public void testSetDataLimit() throws Exception { startOffloadHardwareInterface(); final long limit = 12345; mOffloadHw.setDataLimit(RMNET0, limit); verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any()); } @Test public void testSetUpstreamParameters() throws Exception { startOffloadHardwareInterface(); final String v4addr = "192.168.10.1"; final String v4gateway = "192.168.10.255"; final ArrayList<String> v6gws = new ArrayList<>(0); v6gws.add("2001:db8::1"); mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws); verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), eq(v6gws), any()); final ArgumentCaptor<ArrayList<String>> mArrayListCaptor = ArgumentCaptor.forClass(ArrayList.class); mOffloadHw.setUpstreamParameters(null, null, null, null); verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""), mArrayListCaptor.capture(), any()); assertEquals(mArrayListCaptor.getValue().size(), 0); } @Test public void testUpdateDownstreamPrefix() throws Exception { startOffloadHardwareInterface(); final String ifName = "wlan1"; final String prefix = "192.168.43.0/24"; mOffloadHw.addDownstreamPrefix(ifName, prefix); verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any()); mOffloadHw.removeDownstreamPrefix(ifName, prefix); verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any()); } @Test public void testTetheringOffloadCallback() throws Exception { startOffloadHardwareInterface(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); mTestLooper.dispatchAll(); verify(mControlCallback).onStarted(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR); mTestLooper.dispatchAll(); verify(mControlCallback).onStoppedError(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED); mTestLooper.dispatchAll(); verify(mControlCallback).onStoppedUnsupported(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE); mTestLooper.dispatchAll(); verify(mControlCallback).onSupportAvailable(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED); mTestLooper.dispatchAll(); verify(mControlCallback).onStoppedLimitReached(); final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP); mTetheringOffloadCallback.updateTimeout(tcpParams); mTestLooper.dispatchAll(); verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP), eq(tcpParams.src.addr), eq(uint16(tcpParams.src.port)), eq(tcpParams.dst.addr), eq(uint16(tcpParams.dst.port))); final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP); mTetheringOffloadCallback.updateTimeout(udpParams); mTestLooper.dispatchAll(); verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP), eq(udpParams.src.addr), eq(uint16(udpParams.src.port)), eq(udpParams.dst.addr), eq(uint16(udpParams.dst.port))); } private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { final NatTimeoutUpdate params = new NatTimeoutUpdate(); params.proto = proto; params.src.addr = "192.168.43.200"; params.src.port = 100; params.dst.addr = "172.50.46.169"; params.dst.port = 150; return params; } } Loading
packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java +73 −51 Original line number Original line Diff line number Diff line Loading @@ -66,6 +66,7 @@ public class OffloadHardwareInterface { private final Handler mHandler; private final Handler mHandler; private final SharedLog mLog; private final SharedLog mLog; private final Dependencies mDeps; private IOffloadControl mOffloadControl; private IOffloadControl mOffloadControl; private TetheringOffloadCallback mTetheringOffloadCallback; private TetheringOffloadCallback mTetheringOffloadCallback; private ControlCallback mControlCallback; private ControlCallback mControlCallback; Loading Loading @@ -126,8 +127,76 @@ public class OffloadHardwareInterface { } } public OffloadHardwareInterface(Handler h, SharedLog log) { public OffloadHardwareInterface(Handler h, SharedLog log) { this(h, log, new Dependencies(log)); } OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) { mHandler = h; mHandler = h; mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mDeps = deps; } /** Capture OffloadHardwareInterface dependencies, for injection. */ static class Dependencies { private final SharedLog mLog; Dependencies(SharedLog log) { mLog = log; } public IOffloadConfig getOffloadConfig() { try { return IOffloadConfig.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("getIOffloadConfig error " + e); return null; } } public IOffloadControl getOffloadControl() { try { return IOffloadControl.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("tethering offload control not supported: " + e); return null; } } public NativeHandle createConntrackSocket(final int groups) { final FileDescriptor fd; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; } final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); try { Os.bind(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } try { Os.connect(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("connect to kernel fail for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } return new NativeHandle(fd, true); } } } /** Get default value indicating whether offload is supported. */ /** Get default value indicating whether offload is supported. */ Loading @@ -141,13 +210,7 @@ public class OffloadHardwareInterface { * share them with offload management process. * share them with offload management process. */ */ public boolean initOffloadConfig() { public boolean initOffloadConfig() { IOffloadConfig offloadConfig; final IOffloadConfig offloadConfig = mDeps.getOffloadConfig(); try { offloadConfig = IOffloadConfig.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("getIOffloadConfig error " + e); return false; } if (offloadConfig == null) { if (offloadConfig == null) { mLog.e("Could not find IOffloadConfig service"); mLog.e("Could not find IOffloadConfig service"); return false; return false; Loading @@ -159,11 +222,11 @@ public class OffloadHardwareInterface { // // // h2 provides a file descriptor bound to the following netlink groups // h2 provides a file descriptor bound to the following netlink groups // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). final NativeHandle h1 = createConntrackSocket( final NativeHandle h1 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY); if (h1 == null) return false; if (h1 == null) return false; final NativeHandle h2 = createConntrackSocket( final NativeHandle h2 = mDeps.createConntrackSocket( NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY); if (h2 == null) { if (h2 == null) { closeFdInNativeHandle(h1); closeFdInNativeHandle(h1); Loading Loading @@ -198,53 +261,12 @@ public class OffloadHardwareInterface { } } } } private NativeHandle createConntrackSocket(final int groups) { FileDescriptor fd; try { fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER); } catch (ErrnoException e) { mLog.e("Unable to create conntrack socket " + e); return null; } final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups); try { Os.bind(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } try { Os.connect(fd, sockAddr); } catch (ErrnoException | SocketException e) { mLog.e("connect to kernel fail for groups " + groups + " error: " + e); try { SocketUtils.closeSocket(fd); } catch (IOException ie) { // Nothing we can do here } return null; } return new NativeHandle(fd, true); } /** Initialize the tethering offload HAL. */ /** Initialize the tethering offload HAL. */ public boolean initOffloadControl(ControlCallback controlCb) { public boolean initOffloadControl(ControlCallback controlCb) { mControlCallback = controlCb; mControlCallback = controlCb; if (mOffloadControl == null) { if (mOffloadControl == null) { try { mOffloadControl = mDeps.getOffloadControl(); mOffloadControl = IOffloadControl.getService(true /*retry*/); } catch (RemoteException | NoSuchElementException e) { mLog.e("tethering offload control not supported: " + e); return false; } if (mOffloadControl == null) { if (mOffloadControl == null) { mLog.e("tethering IOffloadControl.getService() returned null"); mLog.e("tethering IOffloadControl.getService() returned null"); return false; return false; Loading
packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java 0 → 100644 +215 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; 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.net.util.SharedLog; import android.os.Handler; import android.os.NativeHandle; import android.os.test.TestLooper; import android.system.OsConstants; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @SmallTest public final class OffloadHardwareInterfaceTest { private static final String RMNET0 = "test_rmnet_data0"; private final TestLooper mTestLooper = new TestLooper(); private OffloadHardwareInterface mOffloadHw; private ITetheringOffloadCallback mTetheringOffloadCallback; private OffloadHardwareInterface.ControlCallback mControlCallback; @Mock private IOffloadConfig mIOffloadConfig; @Mock private IOffloadControl mIOffloadControl; @Mock private NativeHandle mNativeHandle; class MyDependencies extends OffloadHardwareInterface.Dependencies { MyDependencies(SharedLog log) { super(log); } @Override public IOffloadConfig getOffloadConfig() { return mIOffloadConfig; } @Override public IOffloadControl getOffloadControl() { return mIOffloadControl; } @Override public NativeHandle createConntrackSocket(final int groups) { return mNativeHandle; } } @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()); } private void startOffloadHardwareInterface() throws Exception { mOffloadHw.initOffloadConfig(); mOffloadHw.initOffloadControl(mControlCallback); final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor = ArgumentCaptor.forClass(ITetheringOffloadCallback.class); verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any()); mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue(); } @Test public void testGetForwardedStats() throws Exception { startOffloadHardwareInterface(); final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0); verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any()); assertNotNull(stats); } @Test public void testSetLocalPrefixes() throws Exception { startOffloadHardwareInterface(); final ArrayList<String> localPrefixes = new ArrayList<>(); localPrefixes.add("127.0.0.0/8"); localPrefixes.add("fe80::/64"); mOffloadHw.setLocalPrefixes(localPrefixes); verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any()); } @Test public void testSetDataLimit() throws Exception { startOffloadHardwareInterface(); final long limit = 12345; mOffloadHw.setDataLimit(RMNET0, limit); verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any()); } @Test public void testSetUpstreamParameters() throws Exception { startOffloadHardwareInterface(); final String v4addr = "192.168.10.1"; final String v4gateway = "192.168.10.255"; final ArrayList<String> v6gws = new ArrayList<>(0); v6gws.add("2001:db8::1"); mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws); verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway), eq(v6gws), any()); final ArgumentCaptor<ArrayList<String>> mArrayListCaptor = ArgumentCaptor.forClass(ArrayList.class); mOffloadHw.setUpstreamParameters(null, null, null, null); verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""), mArrayListCaptor.capture(), any()); assertEquals(mArrayListCaptor.getValue().size(), 0); } @Test public void testUpdateDownstreamPrefix() throws Exception { startOffloadHardwareInterface(); final String ifName = "wlan1"; final String prefix = "192.168.43.0/24"; mOffloadHw.addDownstreamPrefix(ifName, prefix); verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any()); mOffloadHw.removeDownstreamPrefix(ifName, prefix); verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any()); } @Test public void testTetheringOffloadCallback() throws Exception { startOffloadHardwareInterface(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED); mTestLooper.dispatchAll(); verify(mControlCallback).onStarted(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR); mTestLooper.dispatchAll(); verify(mControlCallback).onStoppedError(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED); mTestLooper.dispatchAll(); verify(mControlCallback).onStoppedUnsupported(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE); mTestLooper.dispatchAll(); verify(mControlCallback).onSupportAvailable(); mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED); mTestLooper.dispatchAll(); verify(mControlCallback).onStoppedLimitReached(); final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP); mTetheringOffloadCallback.updateTimeout(tcpParams); mTestLooper.dispatchAll(); verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP), eq(tcpParams.src.addr), eq(uint16(tcpParams.src.port)), eq(tcpParams.dst.addr), eq(uint16(tcpParams.dst.port))); final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP); mTetheringOffloadCallback.updateTimeout(udpParams); mTestLooper.dispatchAll(); verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP), eq(udpParams.src.addr), eq(uint16(udpParams.src.port)), eq(udpParams.dst.addr), eq(uint16(udpParams.dst.port))); } private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) { final NatTimeoutUpdate params = new NatTimeoutUpdate(); params.proto = proto; params.src.addr = "192.168.43.200"; params.src.port = 100; params.dst.addr = "172.50.46.169"; params.dst.port = 150; return params; } }