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 --- .../com/android/intentresolver/ChooserHelper.kt | 9 +++ .../com/android/intentresolver/SecureSettings.kt | 27 ------- .../intentresolver/platform/NearbyShareModule.kt | 2 +- .../platform/PlatformSecureSettings.kt | 46 ----------- .../intentresolver/platform/SecureSettings.kt | 41 ---------- .../platform/SecureSettingsModule.kt | 30 ------- .../intentresolver/platform/SettingsImpl.kt | 59 ++++++++++++++ .../intentresolver/platform/SettingsModule.kt | 33 ++++++++ .../intentresolver/platform/SettingsProxy.kt | 92 ++++++++++++++++++++++ 9 files changed, 194 insertions(+), 145 deletions(-) delete mode 100644 java/src/com/android/intentresolver/SecureSettings.kt delete mode 100644 java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt delete mode 100644 java/src/com/android/intentresolver/platform/SecureSettings.kt delete mode 100644 java/src/com/android/intentresolver/platform/SecureSettingsModule.kt create mode 100644 java/src/com/android/intentresolver/platform/SettingsImpl.kt create mode 100644 java/src/com/android/intentresolver/platform/SettingsModule.kt create mode 100644 java/src/com/android/intentresolver/platform/SettingsProxy.kt (limited to 'java/src') diff --git a/java/src/com/android/intentresolver/ChooserHelper.kt b/java/src/com/android/intentresolver/ChooserHelper.kt index 6317ee1d..312911a6 100644 --- a/java/src/com/android/intentresolver/ChooserHelper.kt +++ b/java/src/com/android/intentresolver/ChooserHelper.kt @@ -18,6 +18,7 @@ package com.android.intentresolver import android.app.Activity import android.os.UserHandle +import android.provider.Settings import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.viewModels @@ -30,6 +31,7 @@ import com.android.intentresolver.annotation.JavaInterop import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.ActivityResultRepository import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.PendingSelectionCallbackRepository import com.android.intentresolver.data.model.ChooserRequest +import com.android.intentresolver.platform.GlobalSettings import com.android.intentresolver.ui.viewmodel.ChooserViewModel import com.android.intentresolver.validation.Invalid import com.android.intentresolver.validation.Valid @@ -84,6 +86,7 @@ constructor( hostActivity: Activity, private val activityResultRepo: ActivityResultRepository, private val pendingSelectionCallbackRepo: PendingSelectionCallbackRepository, + private val globalSettings: GlobalSettings, ) : DefaultLifecycleObserver { // This is guaranteed by Hilt, since only a ComponentActivity is injectable. private val activity: ComponentActivity = hostActivity as ComponentActivity @@ -124,6 +127,12 @@ constructor( return } + if (globalSettings.getBooleanOrNull(Settings.Global.SECURE_FRP_MODE) == true) { + Log.e(TAG, "Sharing disabled due to active FRP lock.") + activity.finish() + return + } + when (val request = viewModel.initialRequest) { is Valid -> initializeActivity(request) is Invalid -> reportErrorsAndFinish(request) diff --git a/java/src/com/android/intentresolver/SecureSettings.kt b/java/src/com/android/intentresolver/SecureSettings.kt deleted file mode 100644 index 1e938895..00000000 --- a/java/src/com/android/intentresolver/SecureSettings.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2023 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 - -import android.content.ContentResolver -import android.provider.Settings - -/** A proxy class for secure settings, for easier testing. */ -open class SecureSettings { - open fun getString(resolver: ContentResolver, name: String): String? { - return Settings.Secure.getString(resolver, name) - } -} diff --git a/java/src/com/android/intentresolver/platform/NearbyShareModule.kt b/java/src/com/android/intentresolver/platform/NearbyShareModule.kt index 6cb30b41..1e4b5241 100644 --- a/java/src/com/android/intentresolver/platform/NearbyShareModule.kt +++ b/java/src/com/android/intentresolver/platform/NearbyShareModule.kt @@ -41,7 +41,7 @@ object NearbyShareModule { fun nearbyShareComponent(@ApplicationOwned resources: Resources, settings: SecureSettings) = Optional.ofNullable( ComponentName.unflattenFromString( - settings.getString(NEARBY_SHARING_COMPONENT)?.ifEmpty { null } + settings.getStringOrNull(NEARBY_SHARING_COMPONENT)?.ifEmpty { null } ?: resources.getString(R.string.config_defaultNearbySharingComponent), ) ) diff --git a/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt b/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt deleted file mode 100644 index 0c802c97..00000000 --- a/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt +++ /dev/null @@ -1,46 +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 android.content.ContentResolver -import android.provider.Settings -import javax.inject.Inject - -/** - * Implements [SecureSettings] backed by Settings.Secure and a ContentResolver. - * - * These methods make Binder calls and may block, so use on the Main thread should be avoided. - */ -class PlatformSecureSettings @Inject constructor(private val resolver: ContentResolver) : - SecureSettings { - - override fun getString(name: String): String? { - return Settings.Secure.getString(resolver, name) - } - - override fun getInt(name: String): Int? { - return runCatching { Settings.Secure.getInt(resolver, name) }.getOrNull() - } - - override fun getLong(name: String): Long? { - return runCatching { Settings.Secure.getLong(resolver, name) }.getOrNull() - } - - override fun getFloat(name: String): Float? { - return runCatching { Settings.Secure.getFloat(resolver, name) }.getOrNull() - } -} diff --git a/java/src/com/android/intentresolver/platform/SecureSettings.kt b/java/src/com/android/intentresolver/platform/SecureSettings.kt deleted file mode 100644 index 8a1dc531..00000000 --- a/java/src/com/android/intentresolver/platform/SecureSettings.kt +++ /dev/null @@ -1,41 +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 android.provider.Settings.SettingNotFoundException - -/** - * A component which provides access to values from [android.provider.Settings.Secure]. - * - * All methods return nullable types instead of throwing [SettingNotFoundException] which yields - * cleaner, more idiomatic Kotlin code: - * - * // apply a default: val foo = settings.getInt(FOO) ?: DEFAULT_FOO - * - * // assert if missing: val required = settings.getInt(REQUIRED_VALUE) ?: error("required value - * missing") - */ -interface SecureSettings { - - fun getString(name: String): String? - - fun getInt(name: String): Int? - - fun getLong(name: String): Long? - - fun getFloat(name: String): Float? -} diff --git a/java/src/com/android/intentresolver/platform/SecureSettingsModule.kt b/java/src/com/android/intentresolver/platform/SecureSettingsModule.kt deleted file mode 100644 index fa3ee4fe..00000000 --- a/java/src/com/android/intentresolver/platform/SecureSettingsModule.kt +++ /dev/null @@ -1,30 +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 dagger.Binds -import dagger.Module -import dagger.Reusable -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -interface SecureSettingsModule { - - @Binds @Reusable fun secureSettings(settings: PlatformSecureSettings): SecureSettings -} diff --git a/java/src/com/android/intentresolver/platform/SettingsImpl.kt b/java/src/com/android/intentresolver/platform/SettingsImpl.kt new file mode 100644 index 00000000..c7ff3521 --- /dev/null +++ b/java/src/com/android/intentresolver/platform/SettingsImpl.kt @@ -0,0 +1,59 @@ +/* + * 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 android.content.ContentResolver +import android.provider.Settings +import javax.inject.Inject + +object SettingsImpl { + /** An implementation of GlobalSettings which forwards to [Settings.Global] */ + class Global @Inject constructor(private val contentResolver: ContentResolver) : + GlobalSettings { + override fun getStringOrNull(name: String): String? { + return Settings.Global.getString(contentResolver, name) + } + + override fun putString(name: String, value: String): Boolean { + return Settings.Global.putString(contentResolver, name, value) + } + } + + /** An implementation of SecureSettings which forwards to [Settings.Secure] */ + class Secure @Inject constructor(private val contentResolver: ContentResolver) : + SecureSettings { + override fun getStringOrNull(name: String): String? { + return Settings.Secure.getString(contentResolver, name) + } + + override fun putString(name: String, value: String): Boolean { + return Settings.Secure.putString(contentResolver, name, value) + } + } + + /** An implementation of SystemSettings which forwards to [Settings.System] */ + class System @Inject constructor(private val contentResolver: ContentResolver) : + SystemSettings { + override fun getStringOrNull(name: String): String? { + return Settings.System.getString(contentResolver, name) + } + + override fun putString(name: String, value: String): Boolean { + return Settings.System.putString(contentResolver, name, value) + } + } +} diff --git a/java/src/com/android/intentresolver/platform/SettingsModule.kt b/java/src/com/android/intentresolver/platform/SettingsModule.kt new file mode 100644 index 00000000..3d5c50da --- /dev/null +++ b/java/src/com/android/intentresolver/platform/SettingsModule.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.Binds +import dagger.Module +import dagger.Reusable +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +interface SettingsModule { + @Binds @Reusable fun globalSettings(settings: SettingsImpl.Global): GlobalSettings + + @Binds @Reusable fun secureSettings(settings: SettingsImpl.Secure): SecureSettings + + @Binds @Reusable fun systemSettings(settings: SettingsImpl.System): SystemSettings +} diff --git a/java/src/com/android/intentresolver/platform/SettingsProxy.kt b/java/src/com/android/intentresolver/platform/SettingsProxy.kt new file mode 100644 index 00000000..d97a0414 --- /dev/null +++ b/java/src/com/android/intentresolver/platform/SettingsProxy.kt @@ -0,0 +1,92 @@ +/* + * 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 + +/** A proxy to Settings.Global */ +interface GlobalSettings : SettingsProxy + +/** A proxy to Settings.Secure */ +interface SecureSettings : SettingsProxy + +/** A proxy to Settings.System */ +interface SystemSettings : SettingsProxy + +/** A generic Settings proxy interface */ +sealed interface SettingsProxy { + + /** Returns the String value set for the given settings key, or null if no value exists. */ + fun getStringOrNull(name: String): String? + + /** + * Writes a new string value for the given settings key. + * + * @return true if the value did not previously exist or was modified + */ + fun putString(name: String, value: String): Boolean + + /** + * Returns the Int value for the given settings key or null if no value exists or it cannot be + * interpreted as an Int. + */ + fun getIntOrNull(name: String): Int? = getStringOrNull(name)?.toIntOrNull() + + /** + * Writes a new int value for the given settings key. + * + * @return true if the value did not previously exist or was modified + */ + fun putInt(name: String, value: Int): Boolean = putString(name, value.toString()) + + /** + * Returns the Boolean value for the given settings key or null if no value exists or it cannot + * be interpreted as a Boolean. + */ + fun getBooleanOrNull(name: String): Boolean? = getIntOrNull(name)?.let { it != 0 } + + /** + * Writes a new Boolean value for the given settings key. + * + * @return true if the value did not previously exist or was modified + */ + fun putBoolean(name: String, value: Boolean): Boolean = putInt(name, if (value) 1 else 0) + + /** + * Returns the Long value for the given settings key or null if no value exists or it cannot be + * interpreted as a Long. + */ + fun getLongOrNull(name: String): Long? = getStringOrNull(name)?.toLongOrNull() + + /** + * Writes a new Long value for the given settings key. + * + * @return true if the value did not previously exist or was modified + */ + fun putLong(name: String, value: Long): Boolean = putString(name, value.toString()) + + /** + * Returns the Float value for the given settings key or null if no value exists or it cannot be + * interpreted as a Float. + */ + fun getFloatOrNull(name: String): Float? = getStringOrNull(name)?.toFloatOrNull() + + /** + * Writes a new float value for the given settings key. + * + * @return true if the value did not previously exist or was modified + */ + fun putFloat(name: String, value: Float): Boolean = putString(name, value.toString()) +} -- cgit v1.2.3-59-g8ed1b