From ce194e0659c92f4b4bc71d1842c449df1013be14 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 21 Feb 2018 14:47:09 -0800 Subject: [PATCH] Allow callers to synchronously block for shutdown 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 --- .../net/java/android/net/ip/IpClient.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index d3a97b3851f42..1f370a5742312 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -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(); }