Merge "Quit statemachine when dhcp server is stopped"
diff --git a/src/android/net/dhcp/DhcpServer.java b/src/android/net/dhcp/DhcpServer.java
index 6c95b5a..60c7323 100644
--- a/src/android/net/dhcp/DhcpServer.java
+++ b/src/android/net/dhcp/DhcpServer.java
@@ -99,6 +99,7 @@
     private static final int CMD_UPDATE_PARAMS = 3;
     @VisibleForTesting
     protected static final int CMD_RECEIVE_PACKET = 4;
+    private static final int CMD_TERMINATE_AFTER_STOP = 5;
 
     @NonNull
     private final Context mContext;
@@ -362,10 +363,12 @@
      * Stop listening for packets.
      *
      * <p>As the server is stopped asynchronously, some packets may still be processed shortly after
-     * calling this method.
+     * calling this method. The server will also be cleaned up and can't be started again, even if
+     * it was already stopped.
      */
     void stop(@Nullable INetworkStackStatusCallback cb) {
         sendMessage(CMD_STOP_DHCP_SERVER, cb);
+        sendMessage(CMD_TERMINATE_AFTER_STOP);
     }
 
     private void maybeNotifyStatus(@Nullable INetworkStackStatusCallback cb, int statusCode) {
@@ -407,6 +410,9 @@
                     mEventCallbacks = obj.second;
                     transitionTo(mRunningState);
                     return HANDLED;
+                case CMD_TERMINATE_AFTER_STOP:
+                    quit();
+                    return HANDLED;
                 default:
                     return NOT_HANDLED;
             }
diff --git a/tests/unit/src/android/net/dhcp/DhcpServerTest.java b/tests/unit/src/android/net/dhcp/DhcpServerTest.java
index d313b94..0d3a3ee 100644
--- a/tests/unit/src/android/net/dhcp/DhcpServerTest.java
+++ b/tests/unit/src/android/net/dhcp/DhcpServerTest.java
@@ -53,6 +53,7 @@
 import android.net.dhcp.DhcpServer.Clock;
 import android.net.dhcp.DhcpServer.Dependencies;
 import android.net.util.SharedLog;
+import android.os.ConditionVariable;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
@@ -130,11 +131,30 @@
     private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor;
 
     @NonNull
-    private DhcpServer mServer;
+    private MyDhcpServer mServer;
 
     @Nullable
     private String mPrevShareClassloaderProp;
 
+    private class MyDhcpServer extends DhcpServer {
+        private final ConditionVariable mCv = new ConditionVariable(false);
+
+        MyDhcpServer(Context context, String ifName, DhcpServingParams params, SharedLog log,
+                Dependencies deps) {
+            super(context, ifName, params, log, deps);
+        }
+
+        @Override
+        protected void onQuitting() {
+            super.onQuitting();
+            mCv.open();
+        }
+
+        public void waitForShutdown() {
+            assertTrue(mCv.block(TEST_TIMEOUT_MS));
+        }
+    }
+
     private final INetworkStackStatusCallback mAssertSuccessCallback =
             new INetworkStackStatusCallback.Stub() {
         @Override
@@ -183,7 +203,7 @@
         when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME);
         when(mPacketListener.start()).thenReturn(true);
 
-        mServer = new DhcpServer(mContext, TEST_IFACE, makeServingParams(),
+        mServer = new MyDhcpServer(mContext, TEST_IFACE, makeServingParams(),
                 new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps);
     }
 
@@ -191,7 +211,7 @@
     public void tearDown() throws Exception {
         verify(mRepository, never()).addLeaseCallbacks(eq(null));
         mServer.stop(mAssertSuccessCallback);
-        HandlerUtilsKt.waitForIdle(mServer.getHandler(), TEST_TIMEOUT_MS);
+        mServer.waitForShutdown();
         verify(mPacketListener, times(1)).stop();
     }