From 5c9c3a7462dc45907ee30516f43aff68ada3d06d Mon Sep 17 00:00:00 2001 From: Mark Renouf Date: Fri, 24 May 2024 09:34:52 -0400 Subject: Disable sharing when device is under active FRP lock Prevent FRP bypass scenarios involving share intents This CL includes a cleanup of our Settings abstraction to cover Global, Secure and System, and updates existing tests. Bug: 327645387 Test: atest IntentResolver-tests-unit Test: atest ChooserActivityTest#chooserDisabledWhileDeviceFrpLocked Flag: EXEMPT refactor Change-Id: I928b6ea68aa8d6d710dc51eb70acd2cc2ec682c3 --- .../intentresolver/ChooserActivityTest.java | 15 ++++ .../intentresolver/platform/FakeSettingsModule.kt | 33 +++++++++ .../intentresolver/platform/FakeSecureSettings.kt | 60 ---------------- .../intentresolver/platform/FakeSettings.kt | 43 ++++++++++++ .../platform/FakeSecureSettingsTest.kt | 77 -------------------- .../intentresolver/platform/FakeSettingsTest.kt | 81 ++++++++++++++++++++++ .../platform/NearbyShareModuleTest.kt | 6 +- 7 files changed, 175 insertions(+), 140 deletions(-) create mode 100644 tests/activity/src/com/android/intentresolver/platform/FakeSettingsModule.kt delete mode 100644 tests/shared/src/com/android/intentresolver/platform/FakeSecureSettings.kt create mode 100644 tests/shared/src/com/android/intentresolver/platform/FakeSettings.kt delete mode 100644 tests/unit/src/com/android/intentresolver/platform/FakeSecureSettingsTest.kt create mode 100644 tests/unit/src/com/android/intentresolver/platform/FakeSettingsTest.kt (limited to 'tests') diff --git a/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java b/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java index 66f7650d..24b7fb12 100644 --- a/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java +++ b/tests/activity/src/com/android/intentresolver/ChooserActivityTest.java @@ -91,6 +91,7 @@ import android.os.UserHandle; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DeviceConfig; +import android.provider.Settings; import android.service.chooser.ChooserAction; import android.service.chooser.ChooserTarget; import android.text.Spannable; @@ -130,6 +131,7 @@ import com.android.intentresolver.logging.EventLog; import com.android.intentresolver.logging.FakeEventLog; import com.android.intentresolver.platform.AppPredictionAvailable; import com.android.intentresolver.platform.AppPredictionModule; +import com.android.intentresolver.platform.GlobalSettings; import com.android.intentresolver.platform.ImageEditor; import com.android.intentresolver.platform.ImageEditorModule; import com.android.intentresolver.shared.model.User; @@ -233,6 +235,9 @@ public class ChooserActivityTest { @ApplicationContext Context mContext; + @Inject + GlobalSettings mGlobalSettings; + /** An arbitrary pre-installed activity that handles this type of intent. */ @BindValue @ImageEditor @@ -2754,6 +2759,16 @@ public class ChooserActivityTest { assertThat(activity.getCurrentUserHandle(), is(PERSONAL_USER_HANDLE)); } + @Test + public void chooserDisabledWhileDeviceFrpLocked() { + mGlobalSettings.putBoolean(Settings.Global.SECURE_FRP_MODE, true); + Intent viewIntent = createSendTextIntent(); + ChooserWrapperActivity activity = mActivityRule.launchActivity( + Intent.createChooser(viewIntent, "chooser test")); + waitForIdle(); + assertTrue(activity.isFinishing()); + } + private Intent createChooserIntent(Intent intent, Intent[] initialIntents) { Intent chooserIntent = new Intent(); chooserIntent.setAction(Intent.ACTION_CHOOSER); diff --git a/tests/activity/src/com/android/intentresolver/platform/FakeSettingsModule.kt b/tests/activity/src/com/android/intentresolver/platform/FakeSettingsModule.kt new file mode 100644 index 00000000..9295f054 --- /dev/null +++ b/tests/activity/src/com/android/intentresolver/platform/FakeSettingsModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.platform + +import dagger.Module +import dagger.Provides +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import javax.inject.Singleton + +@Module +@TestInstallIn(components = [SingletonComponent::class], replaces = [SettingsModule::class]) +object FakeSettingsModule { + @Provides @Singleton fun secureSettings(): SecureSettings = FakeSettings() + + @Provides @Singleton fun systemSettings(): SystemSettings = FakeSettings() + + @Provides @Singleton fun globalSettings(): GlobalSettings = FakeSettings() +} diff --git a/tests/shared/src/com/android/intentresolver/platform/FakeSecureSettings.kt b/tests/shared/src/com/android/intentresolver/platform/FakeSecureSettings.kt deleted file mode 100644 index 862be76f..00000000 --- a/tests/shared/src/com/android/intentresolver/platform/FakeSecureSettings.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.intentresolver.platform - -/** - * Creates a SecureSettings instance with predefined values: - * - * val settings = fakeSecureSettings { - * putString("stringValue", "example") - * putInt("intValue", 42) - * } - */ -fun fakeSecureSettings(block: FakeSecureSettings.Builder.() -> Unit): SecureSettings { - return FakeSecureSettings.Builder().apply(block).build() -} - -/** An in memory implementation of [SecureSettings]. */ -class FakeSecureSettings private constructor(private val map: Map) : - SecureSettings { - - override fun getString(name: String): String? = map[name] - override fun getInt(name: String): Int? = getString(name)?.toIntOrNull() - override fun getLong(name: String): Long? = getString(name)?.toLongOrNull() - override fun getFloat(name: String): Float? = getString(name)?.toFloatOrNull() - - class Builder { - private val map = mutableMapOf() - - fun putString(name: String, value: String) { - map[name] = value - } - fun putInt(name: String, value: Int) { - map[name] = value.toString() - } - fun putLong(name: String, value: Long) { - map[name] = value.toString() - } - fun putFloat(name: String, value: Float) { - map[name] = value.toString() - } - - fun build(): SecureSettings { - return FakeSecureSettings(map.toMap()) - } - } -} diff --git a/tests/shared/src/com/android/intentresolver/platform/FakeSettings.kt b/tests/shared/src/com/android/intentresolver/platform/FakeSettings.kt new file mode 100644 index 00000000..55cd7127 --- /dev/null +++ b/tests/shared/src/com/android/intentresolver/platform/FakeSettings.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.platform + +/** + * Creates a Settings instance with predefined values: + * + * val settings: SecureSettings = fakeSettings { + * putString("stringValue", "example") + * putInt("intValue", 42) + * } + */ +inline fun fakeSettings(block: SettingsProxy.() -> Unit): T { + return FakeSettings(mutableMapOf()).apply(block) as T +} + +/** A memory-only implementation of [SettingsProxy]. */ +class FakeSettings( + private val map: MutableMap, +) : GlobalSettings, SecureSettings, SystemSettings { + constructor() : this(mutableMapOf()) + + override fun getStringOrNull(name: String): String? = map[name] + + override fun putString(name: String, value: String): Boolean { + map[name] = value + return true + } +} diff --git a/tests/unit/src/com/android/intentresolver/platform/FakeSecureSettingsTest.kt b/tests/unit/src/com/android/intentresolver/platform/FakeSecureSettingsTest.kt deleted file mode 100644 index fd74b50a..00000000 --- a/tests/unit/src/com/android/intentresolver/platform/FakeSecureSettingsTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.intentresolver.platform - -import com.google.common.truth.Truth.assertThat - -class FakeSecureSettingsTest { - - private val secureSettings = fakeSecureSettings { - putInt(intKey, intVal) - putString(stringKey, stringVal) - putFloat(floatKey, floatVal) - putLong(longKey, longVal) - } - - fun testExpectedValues_returned() { - assertThat(secureSettings.getInt(intKey)).isEqualTo(intVal) - assertThat(secureSettings.getString(stringKey)).isEqualTo(stringVal) - assertThat(secureSettings.getFloat(floatKey)).isEqualTo(floatVal) - assertThat(secureSettings.getLong(longKey)).isEqualTo(longVal) - } - - fun testUndefinedValues_returnNull() { - assertThat(secureSettings.getInt("unknown")).isNull() - assertThat(secureSettings.getString("unknown")).isNull() - assertThat(secureSettings.getFloat("unknown")).isNull() - assertThat(secureSettings.getLong("unknown")).isNull() - } - - /** - * FakeSecureSettings models the real secure settings by storing values in String form. The - * value is returned if/when it can be parsed from the string value, otherwise null. - */ - fun testMismatchedTypes() { - assertThat(secureSettings.getString(intKey)).isEqualTo(intVal.toString()) - assertThat(secureSettings.getString(floatKey)).isEqualTo(floatVal.toString()) - assertThat(secureSettings.getString(longKey)).isEqualTo(longVal.toString()) - - assertThat(secureSettings.getInt(stringKey)).isNull() - assertThat(secureSettings.getLong(stringKey)).isNull() - assertThat(secureSettings.getFloat(stringKey)).isNull() - - assertThat(secureSettings.getInt(longKey)).isNull() - assertThat(secureSettings.getFloat(longKey)).isNull() // TODO: verify Long.MAX > Float.MAX ? - - assertThat(secureSettings.getLong(floatKey)).isNull() // TODO: or is Float.MAX > Long.MAX? - assertThat(secureSettings.getInt(floatKey)).isNull() - } - - companion object Data { - const val intKey = "int" - const val intVal = Int.MAX_VALUE - - const val stringKey = "string" - const val stringVal = "String" - - const val floatKey = "float" - const val floatVal = Float.MAX_VALUE - - const val longKey = "long" - const val longVal = Long.MAX_VALUE - } -} diff --git a/tests/unit/src/com/android/intentresolver/platform/FakeSettingsTest.kt b/tests/unit/src/com/android/intentresolver/platform/FakeSettingsTest.kt new file mode 100644 index 00000000..82daca55 --- /dev/null +++ b/tests/unit/src/com/android/intentresolver/platform/FakeSettingsTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.platform + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class FakeSettingsTest { + + private val settings: FakeSettings = fakeSettings { + putInt(intKey, intVal) + putString(stringKey, stringVal) + putFloat(floatKey, floatVal) + putLong(longKey, longVal) + } + + @Test + fun testExpectedValues_returned() { + assertThat(settings.getIntOrNull(intKey)).isEqualTo(intVal) + assertThat(settings.getStringOrNull(stringKey)).isEqualTo(stringVal) + assertThat(settings.getFloatOrNull(floatKey)).isEqualTo(floatVal) + assertThat(settings.getLongOrNull(longKey)).isEqualTo(longVal) + } + + @Test + fun testUndefinedValues_returnNull() { + assertThat(settings.getIntOrNull("unknown")).isNull() + assertThat(settings.getStringOrNull("unknown")).isNull() + assertThat(settings.getFloatOrNull("unknown")).isNull() + assertThat(settings.getLongOrNull("unknown")).isNull() + } + + /** + * FakeSecureSettings models the real secure settings by storing values in String form. The + * value is returned if/when it can be parsed from the string value, otherwise null. + */ + @Test + fun testMismatchedTypes() { + assertThat(settings.getStringOrNull(intKey)).isEqualTo(intVal.toString()) + assertThat(settings.getStringOrNull(floatKey)).isEqualTo(floatVal.toString()) + assertThat(settings.getStringOrNull(longKey)).isEqualTo(longVal.toString()) + + assertThat(settings.getIntOrNull(stringKey)).isNull() + assertThat(settings.getLongOrNull(stringKey)).isNull() + assertThat(settings.getFloatOrNull(stringKey)).isNull() + + assertThat(settings.getIntOrNull(longKey)).isNull() + assertThat(settings.getFloatOrNull(longKey)).isWithin(0.00001f).of(Long.MAX_VALUE.toFloat()) + + assertThat(settings.getLongOrNull(floatKey)).isNull() + assertThat(settings.getIntOrNull(floatKey)).isNull() + } + + companion object Data { + const val intKey = "int" + const val intVal = Int.MAX_VALUE + + const val stringKey = "string" + const val stringVal = "String" + + const val floatKey = "float" + const val floatVal = Float.MAX_VALUE + + const val longKey = "long" + const val longVal = Long.MAX_VALUE + } +} diff --git a/tests/unit/src/com/android/intentresolver/platform/NearbyShareModuleTest.kt b/tests/unit/src/com/android/intentresolver/platform/NearbyShareModuleTest.kt index 71ef2919..6e5c97c2 100644 --- a/tests/unit/src/com/android/intentresolver/platform/NearbyShareModuleTest.kt +++ b/tests/unit/src/com/android/intentresolver/platform/NearbyShareModuleTest.kt @@ -49,7 +49,7 @@ class NearbyShareModuleTest { @Test fun valueIsAbsent_whenUnset() { - val secureSettings = fakeSecureSettings {} + val secureSettings: SecureSettings = fakeSettings {} val resources = context.fakeResources { addOverride(R.string.config_defaultNearbySharingComponent, "") } @@ -59,7 +59,7 @@ class NearbyShareModuleTest { @Test fun defaultValue_readFromResources() { - val secureSettings = fakeSecureSettings {} + val secureSettings: SecureSettings = fakeSettings {} val resources = context.fakeResources { addOverride( @@ -76,7 +76,7 @@ class NearbyShareModuleTest { @Test fun secureSettings_overridesDefault() { - val secureSettings = fakeSecureSettings { + val secureSettings: SecureSettings = fakeSettings { putString(Settings.Secure.NEARBY_SHARING_COMPONENT, "com.example/.BComponent") } val resources = -- cgit v1.2.3-59-g8ed1b