Merge "Allow callers to synchronously block for shutdown"
am: 9121322ce7
Change-Id: Ic0293bf12688e785f4942f0985a8470155fe062b
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index d3a97b3..1f370a5 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.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 @@
/**
* 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 @@
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 @@
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 @@
@Override
protected void onQuitting() {
mCallback.onQuit();
+ mShutdownLatch.countDown();
}
// Shut down this IpClient instance altogether.
@@ -712,6 +721,17 @@
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();
}