diff --git a/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java b/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java index c9e75c0642..5eb155152b 100644 --- a/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java +++ b/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java @@ -62,8 +62,8 @@ public class VersionedBroadcastListener { if (DBG) Log.d(mTag, "startListening"); if (mReceiver != null) return; - mReceiver = new Receiver(mTag, mGenerationNumber, mCallback); - mContext.registerReceiver(mReceiver, mFilter, null, mHandler); + mReceiver = new Receiver(mTag, mGenerationNumber, mCallback, mHandler); + mContext.registerReceiver(mReceiver, mFilter); } /** Stop listening to intent broadcast. */ @@ -77,30 +77,35 @@ public class VersionedBroadcastListener { } private static class Receiver extends BroadcastReceiver { - public final String tag; - public final AtomicInteger atomicGenerationNumber; - public final Consumer callback; + final String mTag; + final AtomicInteger mAtomicGenerationNumber; + final Consumer mCallback; // Used to verify this receiver is still current. - public final int generationNumber; + final int mGenerationNumber; + private final Handler mHandler; - Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer callback) { - this.tag = tag; - this.atomicGenerationNumber = atomicGenerationNumber; - this.callback = callback; - generationNumber = atomicGenerationNumber.incrementAndGet(); + Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer callback, + Handler handler) { + mTag = tag; + mAtomicGenerationNumber = atomicGenerationNumber; + mCallback = callback; + mGenerationNumber = atomicGenerationNumber.incrementAndGet(); + mHandler = handler; } @Override public void onReceive(Context context, Intent intent) { - final int currentGenerationNumber = atomicGenerationNumber.get(); + mHandler.post(() -> { + final int currentGenerationNumber = mAtomicGenerationNumber.get(); - if (DBG) { - Log.d(tag, "receiver generationNumber=" + generationNumber - + ", current generationNumber=" + currentGenerationNumber); - } - if (generationNumber != currentGenerationNumber) return; + if (DBG) { + Log.d(mTag, "receiver generationNumber=" + mGenerationNumber + + ", current generationNumber=" + currentGenerationNumber); + } + if (mGenerationNumber != currentGenerationNumber) return; - callback.accept(intent); + mCallback.accept(intent); + }); } } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java index b7dc66e015..ed4f3daec9 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java @@ -16,6 +16,8 @@ package com.android.networkstack.tethering.util; +import static com.android.testutils.HandlerUtils.waitForIdle; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.reset; @@ -23,7 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; -import android.os.Looper; +import android.os.HandlerThread; import android.os.UserHandle; import androidx.test.filters.SmallTest; @@ -33,7 +35,6 @@ import com.android.internal.util.test.BroadcastInterceptingContext; import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -44,9 +45,11 @@ import org.mockito.MockitoAnnotations; public class VersionedBroadcastListenerTest { private static final String TAG = VersionedBroadcastListenerTest.class.getSimpleName(); private static final String ACTION_TEST = "action.test.happy.broadcasts"; + private static final long TEST_TIMEOUT_MS = 10_000L; @Mock private Context mContext; private BroadcastInterceptingContext mServiceContext; + private HandlerThread mHandlerThread; private Handler mHandler; private VersionedBroadcastListener mListener; private int mCallbackCount; @@ -61,18 +64,13 @@ public class VersionedBroadcastListenerTest { } } - @BeforeClass - public static void setUpBeforeClass() throws Exception { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - } - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); reset(mContext); + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); mServiceContext = new MockContext(mContext); - mHandler = new Handler(Looper.myLooper()); mCallbackCount = 0; final IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_TEST); @@ -85,11 +83,15 @@ public class VersionedBroadcastListenerTest { mListener.stopListening(); mListener = null; } + mHandlerThread.quitSafely(); + mHandlerThread.join(TEST_TIMEOUT_MS); } private void sendBroadcast() { final Intent intent = new Intent(ACTION_TEST); mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + // Sending the broadcast is synchronous, but the receiver just posts on the handler + waitForIdle(mHandler, TEST_TIMEOUT_MS); } @Test