diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 6009984842f46..f5f7732141242 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.LinkedList; @@ -343,6 +344,30 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo rawBuilder.append('\0'); } + /** + * Method that waits until all asychronous notifications sent by the native daemon have + * been processed. This method must not be called on the notification thread or an + * exception will be thrown. + */ + public void waitForCallbacks() { + if (Thread.currentThread() == mLooper.getThread()) { + throw new IllegalStateException("Must not call this method on callback thread"); + } + + final CountDownLatch latch = new CountDownLatch(1); + mCallbackHandler.post(new Runnable() { + @Override + public void run() { + latch.countDown(); + } + }); + try { + latch.await(); + } catch (InterruptedException e) { + Slog.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); + } + } + /** * Issue the given command to the native daemon and return a single expected * response. diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index fffd850ac1cba..7458898475797 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1507,6 +1507,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); } + + // Ensure that before we return from this command, any asynchronous + // notifications generated before the command completed have been + // processed by all NetworkManagementEventObservers. + mConnector.waitForCallbacks(); } @Override diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 79b5978998c4c..c2022d5008d8f 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -273,9 +273,6 @@ public class Tethering extends BaseNetworkObserver { // ignore usb0 down after enabling RNDIS // we will handle disconnect in interfaceRemoved instead if (VDBG) Log.d(TAG, "ignore interface down for " + iface); - } else if (isWifi(iface)) { - // handle disconnect in interfaceRemoved - if (VDBG) Log.d(TAG, "ignore interface down for " + iface); } else if (sm != null) { sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN); mIfaces.remove(iface);