From af2670f4279550b5e78f890899e39fc803cb0c9a Mon Sep 17 00:00:00 2001 From: markchien <markchien@google.com> Date: Wed, 22 Jul 2020 21:28:48 +0800 Subject: [PATCH] Always stop dhcp server even it is obsolete If dhcp server is obsolete, explicitly stop it to shut down its thread. Bug: 161418295 Test: atest CtsTetheringTest Change-Id: Ic5b876bd23711ec8d832879a7baee0495246b218 --- Tethering/src/android/net/ip/IpServer.java | 10 ++-- .../unit/src/android/net/ip/IpServerTest.java | 54 +++++++++++++++---- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index a61fcfb819..71fa84ea57 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -422,9 +422,13 @@ public class IpServer extends StateMachine { getHandler().post(() -> { // We are on the handler thread: mDhcpServerStartIndex can be read safely. if (mStartIndex != mDhcpServerStartIndex) { - // This start request is obsolete. When the |server| binder token goes out of - // scope, the garbage collector will finalize it, which causes the network stack - // process garbage collector to collect the server itself. + // This start request is obsolete. Explicitly stop the DHCP server to shut + // down its thread. When the |server| binder token goes out of scope, the + // garbage collector will finalize it, which causes the network stack process + // garbage collector to collect the server itself. + try { + server.stop(null); + } catch (RemoteException e) { } return; } diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 05cf58ab84..e0a1dc7a4a 100644 --- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -49,6 +49,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; @@ -72,6 +73,7 @@ import android.net.MacAddress; import android.net.RouteInfo; import android.net.TetherOffloadRuleParcel; import android.net.TetherStatsParcel; +import android.net.dhcp.DhcpServerCallbacks; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; @@ -162,17 +164,6 @@ public class IpServerTest { private void initStateMachine(int interfaceType, boolean usingLegacyDhcp, boolean usingBpfOffload) throws Exception { - doAnswer(inv -> { - final IDhcpServerCallbacks cb = inv.getArgument(2); - new Thread(() -> { - try { - cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer); - } catch (RemoteException e) { - fail(e.getMessage()); - } - }).run(); - return null; - }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any()); when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon); when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS); @@ -224,6 +215,20 @@ public class IpServerTest { when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); } + private void setUpDhcpServer() throws Exception { + doAnswer(inv -> { + final IDhcpServerCallbacks cb = inv.getArgument(2); + new Thread(() -> { + try { + cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer); + } catch (RemoteException e) { + fail(e.getMessage()); + } + }).run(); + return null; + }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any()); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); @@ -257,6 +262,8 @@ public class IpServerTest { return mTetherConfig; } })); + + setUpDhcpServer(); } @Test @@ -964,6 +971,31 @@ public class IpServerTest { reset(mRaDaemon); } + @Test + public void testStopObsoleteDhcpServer() throws Exception { + final ArgumentCaptor<DhcpServerCallbacks> cbCaptor = + ArgumentCaptor.forClass(DhcpServerCallbacks.class); + doNothing().when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), + cbCaptor.capture()); + initStateMachine(TETHERING_WIFI); + dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED); + verify(mDhcpServer, never()).startWithCallbacks(any(), any()); + + // No stop dhcp server because dhcp server is not created yet. + dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); + verify(mDhcpServer, never()).stop(any()); + + // Stop obsolete dhcp server. + try { + final DhcpServerCallbacks cb = cbCaptor.getValue(); + cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer); + mLooper.dispatchAll(); + } catch (RemoteException e) { + fail(e.getMessage()); + } + verify(mDhcpServer).stop(any()); + } + private void assertDhcpServingParams(final DhcpServingParamsParcel params, final IpPrefix prefix) { // Last address byte is random -- GitLab