OSDN Git Service

Allow callers to synchronously block for shutdown
authorErik Kline <ek@google.com>
Wed, 21 Feb 2018 22:47:09 +0000 (14:47 -0800)
committerErik Kline <ek@google.com>
Thu, 22 Feb 2018 19:14:57 +0000 (11:14 -0800)
Add a simple CountDownLatch and a public method that callers can use
to block until IpClient has cleanly shutdown the state machine.

In cases where IpClients are created and destroyed dynamically for
the same interface name, this can be used to make sure only one
IpClient at a time is touching the given interface.

Test: as follows
    - built
    - flashed
    - booted
    - OTG ethernet works (i.e. client mode)
    - removing and reinserting the ethernet dongle continues
      to show the <-> Ethernet sysui icon and basic network
      connectivity works
    - removing and reinserting the cable (link up/down events)
      also shows the <-> Ethernet sysui icon and basic network
      connectivity works
Bug: 62476366

Change-Id: If4bffd54b7ebc088ec07cac10251e451f8161b6c

services/net/java/android/net/ip/IpClient.java

index d3a97b3..1f370a5 100644 (file)
@@ -72,6 +72,7 @@ import java.util.Objects;
 import java.util.List;
 import java.util.Set;
 import java.util.StringJoiner;
+import java.util.concurrent.CountDownLatch;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -100,6 +101,11 @@ public class IpClient extends StateMachine {
 
     /**
      * Callbacks for handling IpClient events.
+     *
+     * These methods are called by IpClient on its own thread. Implementations
+     * of this class MUST NOT carry out long-running computations or hold locks
+     * for which there might be contention with other code calling public
+     * methods of the same IpClient instance.
      */
     public static class Callback {
         // In order to receive onPreDhcpAction(), call #withPreDhcpAction()
@@ -545,6 +551,7 @@ public class IpClient extends StateMachine {
     private final String mClatInterfaceName;
     @VisibleForTesting
     protected final Callback mCallback;
+    private final CountDownLatch mShutdownLatch;
     private final INetworkManagementService mNwService;
     private final NetlinkTracker mNetlinkTracker;
     private final WakeupMessage mProvisioningTimeoutAlarm;
@@ -597,6 +604,7 @@ public class IpClient extends StateMachine {
         mInterfaceName = ifName;
         mClatInterfaceName = CLAT_PREFIX + ifName;
         mCallback = new LoggingCallbackWrapper(callback);
+        mShutdownLatch = new CountDownLatch(1);
         mNwService = nwService;
 
         mLog = new SharedLog(MAX_LOG_RECORDS, mTag);
@@ -704,6 +712,7 @@ public class IpClient extends StateMachine {
     @Override
     protected void onQuitting() {
         mCallback.onQuit();
+        mShutdownLatch.countDown();
     }
 
     // Shut down this IpClient instance altogether.
@@ -712,6 +721,17 @@ public class IpClient extends StateMachine {
         sendMessage(CMD_TERMINATE_AFTER_STOP);
     }
 
+    // In order to avoid deadlock, this method MUST NOT be called on the
+    // IpClient instance's thread. This prohibition includes code executed by
+    // when methods on the passed-in IpClient.Callback instance are called.
+    public void awaitShutdown() {
+        try {
+            mShutdownLatch.await();
+        } catch (InterruptedException e) {
+            mLog.e("Interrupted while awaiting shutdown: " + e);
+        }
+    }
+
     public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
         return new ProvisioningConfiguration.Builder();
     }