Merge "Fix RegionSamplingHelper race condition" into tm-qpr-dev am: 6a2f4e2ab5

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20084713

Change-Id: I32c6aa10edb171c4b3b8f50a72bf9dc104d36f1e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Selim Cinek
2022-10-03 13:12:54 +00:00
committed by Automerger Merge Worker
2 changed files with 52 additions and 4 deletions

View File

@@ -217,12 +217,16 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener,
unregisterSamplingListener(); unregisterSamplingListener();
mSamplingListenerRegistered = true; mSamplingListenerRegistered = true;
SurfaceControl wrappedStopLayer = wrap(stopLayerControl); SurfaceControl wrappedStopLayer = wrap(stopLayerControl);
// pass this to background thread to avoid empty Rect race condition
final Rect boundsCopy = new Rect(mSamplingRequestBounds);
mBackgroundExecutor.execute(() -> { mBackgroundExecutor.execute(() -> {
if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) { if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
return; return;
} }
mCompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY, mCompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
wrappedStopLayer, mSamplingRequestBounds); wrappedStopLayer, boundsCopy);
}); });
mRegisteredSamplingBounds.set(mSamplingRequestBounds); mRegisteredSamplingBounds.set(mSamplingRequestBounds);
mRegisteredStopLayer = stopLayerControl; mRegisteredStopLayer = stopLayerControl;

View File

@@ -15,6 +15,7 @@
*/ */
package com.android.systemui.shared.navigationbar package com.android.systemui.shared.navigationbar
import android.graphics.Rect import android.graphics.Rect
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper import android.testing.TestableLooper.RunWithLooper
@@ -24,15 +25,23 @@ import android.view.ViewRootImpl
import androidx.concurrent.futures.DirectExecutor import androidx.concurrent.futures.DirectExecutor
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.* import org.mockito.Mockito.mock
import org.mockito.junit.MockitoJUnit import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@SmallTest @SmallTest
@@ -99,4 +108,39 @@ class RegionSamplingHelperTest : SysuiTestCase() {
regionSamplingHelper.stopAndDestroy() regionSamplingHelper.stopAndDestroy()
verify(compositionListener).unregister(any()) verify(compositionListener).unregister(any())
} }
@Test
fun testCompositionSamplingListener_has_nonEmptyRect() {
// simulate race condition
val fakeExecutor = FakeExecutor(FakeSystemClock()) // pass in as backgroundExecutor
val fakeSamplingCallback = mock(RegionSamplingHelper.SamplingCallback::class.java)
whenever(fakeSamplingCallback.isSamplingEnabled).thenReturn(true)
whenever(wrappedSurfaceControl.isValid).thenReturn(true)
regionSamplingHelper = object : RegionSamplingHelper(sampledView, fakeSamplingCallback,
DirectExecutor.INSTANCE, fakeExecutor, compositionListener) {
override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
return wrappedSurfaceControl
}
}
regionSamplingHelper.setWindowVisible(true)
regionSamplingHelper.start(Rect(0, 0, 100, 100))
// make sure background task is enqueued
assertThat(fakeExecutor.numPending()).isEqualTo(1)
// make sure regionSamplingHelper will have empty Rect
whenever(fakeSamplingCallback.getSampledRegion(any())).thenReturn(Rect(0, 0, 0, 0))
regionSamplingHelper.onLayoutChange(sampledView, 0, 0, 0, 0, 0, 0, 0, 0)
// resume running of background thread
fakeExecutor.runAllReady()
// grab Rect passed into compositionSamplingListener and make sure it's not empty
val argumentGrabber = argumentCaptor<Rect>()
verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl),
argumentGrabber.capture())
assertThat(argumentGrabber.value.isEmpty).isFalse()
}
} }