diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java index 15a5c2773f0b9..c1a23c8ab0035 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java @@ -27,6 +27,7 @@ import com.android.systemui.appops.AppOpsController; import com.android.systemui.dagger.qualifiers.MainHandler; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.util.Assert; import javax.inject.Inject; import javax.inject.Singleton; @@ -121,6 +122,8 @@ public class ForegroundServiceController { * @param active whether the appOpCode is active or not */ void onAppOpChanged(int appOpCode, int uid, String packageName, boolean active) { + Assert.isMainThread(); + int userId = UserHandle.getUserId(uid); // Record active app ops synchronized (mMutex) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 02a3766fb3b6c..0990e2274d8a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -18,6 +18,7 @@ package com.android.systemui; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; +import static junit.framework.TestCase.fail; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -34,12 +35,14 @@ import android.app.Notification; import android.app.NotificationManager; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.widget.RemoteViews; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.messages.nano.SystemMessageProto; import com.android.systemui.appops.AppOpsController; @@ -58,7 +61,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper public class ForegroundServiceControllerTest extends SysuiTestCase { private ForegroundServiceController mFsc; private ForegroundServiceNotificationListener mListener; @@ -69,6 +73,9 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { @Before public void setUp() throws Exception { + // assume the TestLooper is the main looper for these tests + com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + MockitoAnnotations.initMocks(this); mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler); mListener = new ForegroundServiceNotificationListener( @@ -80,6 +87,26 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { mEntryListener = entryListenerCaptor.getValue(); } + @Test + public void testAppOpsChangedCalledFromBgThread() { + try { + // WHEN onAppOpChanged is called from a different thread than the MainLooper + com.android.systemui.util.Assert.sMainLooper = Looper.getMainLooper(); + NotificationEntry entry = createFgEntry(); + mFsc.onAppOpChanged( + AppOpsManager.OP_CAMERA, + entry.getSbn().getUid(), + entry.getSbn().getPackageName(), + true); + + // This test is run on the TestableLooper, which is not the MainLooper, so + // we expect an exception to be thrown + fail("onAppOpChanged shouldn't be allowed to be called from a bg thread."); + } catch (IllegalStateException e) { + // THEN expect an exception + } + } + @Test public void testAppOps_appOpChangedBeforeNotificationExists() { // GIVEN app op exists, but notification doesn't exist in NEM yet