Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efdb8454 authored by Rebecca Silberstein's avatar Rebecca Silberstein
Browse files

NativeDaemonConnector: add waitForCallbacks method

Add a method that allows callers to wait until all unsolicited
responses received from the native daemon during a command are
processed.

When commands are issued to a native daemon (such as netd) through the
NativeDaemonConnector we block until the command response is received.
Any responses or events that are a side-effect (considered
"unsolicited") of the command are placed in a Message and handled as
callbacks. The order of their processing is not guaranteed and, as we
have seen from bugreports, can be handled several seconds
later - causing the SoftAP that was just set up to be torn down
because a late interface down/removed is indistinguishable from a
new interface down/removed.

This CL adds a method that first checks to make sure callback thread
is not the same thread as used for the blocking call.  The new
waitForCallbacks method uses a CountDownLatch to force the calling
thread to wait until all unsolicited responses received from the
native daemon during the execution of the command are handled.

The wifiFirmwareReload method is also updated to use the new
waitForCallbacks method.

BUG: 27857665
Change-Id: I3e22978f720b1cbf57fbb64ad4fea73f8c2d408a
parent d3589ee7
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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.
+5 −0
Original line number Diff line number Diff line
@@ -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