diff options
| author | 2024-10-23 16:02:37 -0700 | |
|---|---|---|
| committer | 2024-10-31 15:54:50 +0000 | |
| commit | f30e1aa0fde7c28693c247bedd6babbb5e3c4c6c (patch) | |
| tree | 0923c193e00ff453565cd17f9326dfcafa86f10d | |
| parent | 59b6c3b31e6f170ea93aff8403b8c76ecd5d214b (diff) | |
Add runtime user process assersions
This change adds assertions in various classes to ensure they are
instantiated only for the expected user.
Test: verified no crashing at runtime which proves the marked classes
are not instantiated on the headless system user
Bug: 357621815
Flag: com.android.systemui.secondary_user_widget_host
Change-Id: Ieed792011da6c7e35a2cd30242c647d006c110d9
11 files changed, 81 insertions, 72 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt index 1e79112eefe3..18513fc496b4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/widgets/CommunalAppWidgetHostTest.kt @@ -21,6 +21,7 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper import com.android.systemui.communal.widgets.CommunalAppWidgetHost import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.applicationCoroutineScope @@ -61,6 +62,7 @@ class CommunalAppWidgetHostTest : SysuiTestCase() { backgroundScope = kosmos.applicationCoroutineScope, hostId = 116, logBuffer = logcatLogBuffer("CommunalAppWidgetHostTest"), + glanceableHubMultiUserHelper = kosmos.fakeGlanceableHubMultiUserHelper, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt index 054e516db943..017c77828cdc 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt @@ -26,6 +26,7 @@ import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.applicationCoroutineScope @@ -84,7 +85,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { any<Int>(), any<UserHandle>(), any<ComponentName>(), - any<Bundle>() + any<Bundle>(), ) ) .thenReturn(true) @@ -96,6 +97,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { appWidgetHost, selectedUserInteractor, logcatLogBuffer("CommunalWidgetHostTest"), + glanceableHubMultiUserHelper = kosmos.fakeGlanceableHubMultiUserHelper, ) } @@ -162,7 +164,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { any<Int>(), any<UserHandle>(), any<ComponentName>(), - any<Bundle>() + any<Bundle>(), ) ) .thenReturn(false) @@ -283,12 +285,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { // all providers are emitted at once assertThat(providerInfoValues).hasSize(2) assertThat(providerInfoValues[1]) - .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo1), - Pair(2, providerInfo2), - ) - ) + .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2))) } @Test @@ -304,12 +301,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Assert that the provider info map is populated val providerInfo by collectLastValue(underTest.appWidgetProviders) assertThat(providerInfo) - .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo1), - Pair(2, providerInfo2), - ) - ) + .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2))) // Host stop listening observer.onHostStopListening() @@ -332,12 +324,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Assert that the provider info map is populated assertThat(providerInfo) - .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo1), - Pair(2, providerInfo2), - ) - ) + .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2))) // Provider info for widget 1 updated val listener = @@ -349,12 +336,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Assert that the update is reflected in the flow assertThat(providerInfo) - .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo3), - Pair(2, providerInfo2), - ) - ) + .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo3), Pair(2, providerInfo2))) } @Test @@ -371,12 +353,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Assert that the provider info map is populated assertThat(providerInfo) - .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo1), - Pair(2, providerInfo2), - ) - ) + .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2))) // Bind a new widget whenever(appWidgetHost.allocateAppWidgetId()).thenReturn(3) @@ -388,11 +365,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Assert that the new provider is reflected in the flow assertThat(providerInfo) .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo1), - Pair(2, providerInfo2), - Pair(3, providerInfo3), - ) + mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2), Pair(3, providerInfo3)) ) } @@ -410,31 +383,21 @@ class CommunalWidgetHostTest : SysuiTestCase() { // Assert that the provider info map is populated assertThat(providerInfo) - .containsExactlyEntriesIn( - mapOf( - Pair(1, providerInfo1), - Pair(2, providerInfo2), - ) - ) + .containsExactlyEntriesIn(mapOf(Pair(1, providerInfo1), Pair(2, providerInfo2))) // Remove widget 1 observer.onDeleteAppWidgetId(1) runCurrent() // Assert that provider info for widget 1 is removed - assertThat(providerInfo) - .containsExactlyEntriesIn( - mapOf( - Pair(2, providerInfo2), - ) - ) + assertThat(providerInfo).containsExactlyEntriesIn(mapOf(Pair(2, providerInfo2))) } private fun selectUser() { kosmos.fakeUserRepository.selectedUser.value = SelectedUserModel( userInfo = UserInfo(0, "Current user", 0), - selectionStatus = SelectionStatus.SELECTION_COMPLETE + selectionStatus = SelectionStatus.SELECTION_COMPLETE, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt index 55fafdff795f..5d4eaf07be25 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/WidgetConfigurationControllerTest.kt @@ -22,6 +22,7 @@ import androidx.activity.ComponentActivity import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.shared.model.fakeGlanceableHubMultiUserHelper import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos @@ -55,7 +56,12 @@ class WidgetConfigurationControllerTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) underTest = - WidgetConfigurationController(ownerActivity, appWidgetHost, kosmos.testDispatcher) + WidgetConfigurationController( + ownerActivity, + { appWidgetHost }, + kosmos.testDispatcher, + kosmos.fakeGlanceableHubMultiUserHelper, + ) } @Test @@ -68,7 +74,7 @@ class WidgetConfigurationControllerTest : SysuiTestCase() { eq(123), anyInt(), eq(WidgetConfigurationController.REQUEST_CODE), - any() + any(), ) ) .thenThrow(ActivityNotFoundException()) diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt index 17f4f0c83d6f..e72088f37fa7 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt @@ -17,6 +17,7 @@ package com.android.systemui.communal.data.db import android.content.Context +import android.os.Process import android.util.Log import androidx.annotation.VisibleForTesting import androidx.room.Database @@ -24,6 +25,7 @@ import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase +import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelperImpl import com.android.systemui.res.R @Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 4) @@ -44,6 +46,11 @@ abstract class CommunalDatabase : RoomDatabase() { * new instance is created. */ fun getInstance(context: Context, callback: Callback? = null): CommunalDatabase { + with(GlanceableHubMultiUserHelperImpl(Process.myUserHandle())) { + // Assert that the database is never accessed from a headless system user. + assertNotInHeadlessSystemUser() + } + if (instance == null) { instance = Room.databaseBuilder( diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index dc248059b3d4..602fe307a1fe 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -40,7 +40,6 @@ import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalWidgetContentModel import com.android.systemui.communal.shared.model.EditModeState -import com.android.systemui.communal.widgets.CommunalAppWidgetHost import com.android.systemui.communal.widgets.EditWidgetsActivityStarter import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.dagger.SysUISingleton @@ -108,7 +107,6 @@ constructor( keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, communalSettingsInteractor: CommunalSettingsInteractor, - private val appWidgetHost: CommunalAppWidgetHost, private val editWidgetsActivityStarter: EditWidgetsActivityStarter, private val userTracker: UserTracker, private val activityStarter: ActivityStarter, @@ -451,7 +449,6 @@ constructor( appWidgetId = widget.appWidgetId, rank = widget.rank, providerInfo = widget.providerInfo, - appWidgetHost = appWidgetHost, inQuietMode = isQuietModeEnabled(widget.providerInfo.profile), size = CommunalContentSize.toSize(widget.spanY), ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt index 4c2c094a4aea..30f580e472e8 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt @@ -23,7 +23,6 @@ import android.content.pm.ApplicationInfo import android.graphics.Bitmap import android.widget.RemoteViews import com.android.systemui.communal.shared.model.CommunalContentSize -import com.android.systemui.communal.widgets.CommunalAppWidgetHost import java.util.UUID /** Encapsulates data for a communal content. */ @@ -60,7 +59,6 @@ sealed interface CommunalContentModel { override val appWidgetId: Int, override val rank: Int, val providerInfo: AppWidgetProviderInfo, - val appWidgetHost: CommunalAppWidgetHost, val inQuietMode: Boolean, override val size: CommunalContentSize, ) : WidgetContent { diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt index 4f9ed2f7dbf8..70e7947e1b70 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHost.kt @@ -18,6 +18,8 @@ package com.android.systemui.communal.widgets import android.appwidget.AppWidgetHost import android.content.Context +import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import javax.annotation.concurrent.GuardedBy @@ -25,7 +27,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow -import com.android.app.tracing.coroutines.launchTraced as launch /** Communal app widget host that creates a [CommunalAppWidgetHostView]. */ class CommunalAppWidgetHost( @@ -33,7 +34,14 @@ class CommunalAppWidgetHost( private val backgroundScope: CoroutineScope, hostId: Int, logBuffer: LogBuffer, + glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper, ) : AppWidgetHost(context, hostId) { + + init { + // The app widget host should never be accessed from a headless system user. + glanceableHubMultiUserHelper.assertNotInHeadlessSystemUser() + } + private val logger = Logger(logBuffer, TAG) private val _appWidgetIdToRemove = MutableSharedFlow<Int>() diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt index 0b8d9775675f..8c745f59e918 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt @@ -26,6 +26,8 @@ import android.os.Bundle import android.os.UserHandle import android.widget.RemoteViews import androidx.annotation.WorkerThread +import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger @@ -38,7 +40,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import com.android.app.tracing.coroutines.launchTraced as launch /** * Widget host that interacts with AppWidget service and host to bind and provide info for widgets @@ -52,7 +53,14 @@ constructor( private val appWidgetHost: CommunalAppWidgetHost, private val selectedUserInteractor: SelectedUserInteractor, @CommunalLog logBuffer: LogBuffer, + glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper, ) : CommunalAppWidgetHost.Observer { + + init { + // The communal widget host should never be accessed from a headless system user. + glanceableHubMultiUserHelper.assertNotInHeadlessSystemUser() + } + companion object { private const val TAG = "CommunalWidgetHost" @@ -96,7 +104,7 @@ constructor( bindWidget( widgetId = id, user = user ?: UserHandle(selectedUserInteractor.getSelectedUserId()), - provider = provider + provider = provider, ) ) { logger.d("Successfully bound the widget $provider") diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt index f4962085000c..a235e7ae2b6a 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetModule.kt @@ -20,6 +20,7 @@ package com.android.systemui.communal.widgets import android.appwidget.AppWidgetManager import android.content.Context import android.content.res.Resources +import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background @@ -46,8 +47,15 @@ interface CommunalWidgetModule { @Application context: Context, @Background backgroundScope: CoroutineScope, @CommunalLog logBuffer: LogBuffer, + glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper, ): CommunalAppWidgetHost { - return CommunalAppWidgetHost(context, backgroundScope, APP_WIDGET_HOST_ID, logBuffer) + return CommunalAppWidgetHost( + context, + backgroundScope, + APP_WIDGET_HOST_ID, + logBuffer, + glanceableHubMultiUserHelper, + ) } @SysUISingleton @@ -58,6 +66,7 @@ interface CommunalWidgetModule { appWidgetHost: CommunalAppWidgetHost, selectedUserInteractor: SelectedUserInteractor, @CommunalLog logBuffer: LogBuffer, + glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper, ): CommunalWidgetHost { return CommunalWidgetHost( applicationScope, @@ -65,6 +74,7 @@ interface CommunalWidgetModule { appWidgetHost, selectedUserInteractor, logBuffer, + glanceableHubMultiUserHelper, ) } diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt index 3e68479e717a..d157cd7acb76 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetConfigurationController.kt @@ -21,8 +21,10 @@ import android.app.ActivityOptions import android.content.ActivityNotFoundException import android.window.SplashScreen import androidx.activity.ComponentActivity +import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelper import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.util.nullableAtomicReference +import dagger.Lazy import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -38,8 +40,9 @@ class WidgetConfigurationController @AssistedInject constructor( @Assisted private val activity: ComponentActivity, - private val appWidgetHost: CommunalAppWidgetHost, - @Background private val bgDispatcher: CoroutineDispatcher + private val appWidgetHostLazy: Lazy<CommunalAppWidgetHost>, + @Background private val bgDispatcher: CoroutineDispatcher, + private val glanceableHubMultiUserHelper: GlanceableHubMultiUserHelper, ) : WidgetConfigurator { @AssistedFactory fun interface Factory { @@ -62,13 +65,21 @@ constructor( } try { - appWidgetHost.startAppWidgetConfigureActivityForResult( - activity, - appWidgetId, - 0, - REQUEST_CODE, - options.toBundle() - ) + // TODO(b/375036327): Add support for widget configuration + if ( + !glanceableHubMultiUserHelper.glanceableHubHsumFlagEnabled || + !glanceableHubMultiUserHelper.isInHeadlessSystemUser() + ) { + with(appWidgetHostLazy.get()) { + startAppWidgetConfigureActivityForResult( + activity, + appWidgetId, + 0, + REQUEST_CODE, + options.toBundle(), + ) + } + } } catch (e: ActivityNotFoundException) { setConfigurationResult(Activity.RESULT_CANCELED) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index 629fda6b610c..1f68195a9acc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -54,7 +54,6 @@ val Kosmos.communalInteractor by Fixture { keyguardInteractor = keyguardInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, communalSettingsInteractor = communalSettingsInteractor, - appWidgetHost = mock(), editWidgetsActivityStarter = editWidgetsActivityStarter, userTracker = userTracker, activityStarter = activityStarter, @@ -62,7 +61,7 @@ val Kosmos.communalInteractor by Fixture { sceneInteractor = sceneInteractor, logBuffer = logcatLogBuffer("CommunalInteractor"), tableLogBuffer = mock(), - managedProfileController = fakeManagedProfileController + managedProfileController = fakeManagedProfileController, ) } |