diff options
author | 2023-02-04 00:26:57 +0000 | |
---|---|---|
committer | 2023-02-18 00:03:33 +0000 | |
commit | dba921871424ac9913344419c7307593522e62b3 (patch) | |
tree | 9449c3622365de24b5af111c3db44321114525e2 | |
parent | ad1faafe3e6bfe3ced93b113a847832c9b8a6bc2 (diff) |
Don't unnecessarily query package metadata for SafetyLabels
Only querying metadata for packages in SafetyLabel display when we know
that the package has permissions that should include safety labels.
Right now that is limited to LOCATION permissions.
As part of this, I consolidated some of the utilities and made it so
there is less branching and less need to check in multiple places
whether the feature is enabled.
Bug: 260873483
Test: atest
Change-Id: I30efd202985fecb95eb919952deaf555d289fc0e
13 files changed, 204 insertions, 275 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt index 543d8eae2..7a817eb6d 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt @@ -74,7 +74,7 @@ private constructor( getInstallSourceInfo(userContext, packageName).installingPackageName) } catch (e: PackageManager.NameNotFoundException) { Log.w(LOG_TAG, "InstallSourceInfo for $packageName not found") - SafetyLabelInfoLiveData.invalidateSingle(packageName to user) + LightInstallSourceInfoLiveData.invalidateSingle(packageName to user) UNKNOWN_INSTALL_SOURCE } postValue(lightInstallSourceInfo) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt index d2ba7031d..e8102c2e0 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt @@ -18,14 +18,10 @@ package com.android.permissioncontroller.permission.data import android.app.Application import android.content.pm.PackageManager -import android.os.PersistableBundle import android.os.UserHandle import android.util.Log -import com.android.permission.safetylabel.DataCategoryConstants -import com.android.permission.safetylabel.DataLabelConstants -import com.android.permission.safetylabel.DataTypeConstants +import com.android.modules.utils.build.SdkLevel import com.android.permission.safetylabel.SafetyLabel -import com.android.permission.safetylabel.SafetyLabel.KEY_VERSION import com.android.permissioncontroller.PermissionControllerApplication import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo import com.android.permissioncontroller.permission.utils.KotlinUtils.isPlaceholderSafetyLabelDataEnabled @@ -83,6 +79,11 @@ private constructor( return } + if (!SdkLevel.isAtLeastU()) { + postValue(SafetyLabelInfo.UNAVAILABLE) + return + } + // TODO(b/261607291): Add support preinstall apps that provide SafetyLabel. Installing // package is null until updated from an app store val installSourcePackageName = lightInstallSourceInfoLiveData.value?.installingPackageName @@ -91,11 +92,16 @@ private constructor( return } + if (isPlaceholderSafetyLabelDataEnabled()) { + postValue(SafetyLabelInfo(SafetyLabel.getPlaceholderSafetyLabel(), + installSourcePackageName)) + return + } + val safetyLabelInfo: SafetyLabelInfo = try { - val metadataBundle: PersistableBundle = getAppMetadata() - val safetyLabel: SafetyLabel? = - SafetyLabel.getSafetyLabelFromMetadata(metadataBundle) + val safetyLabel: SafetyLabel? = SafetyLabel.getSafetyLabelFromMetadata( + app.packageManager.getAppMetadata(packageName)) if (safetyLabel != null) { SafetyLabelInfo(safetyLabel, installSourcePackageName) } else { @@ -109,49 +115,8 @@ private constructor( postValue(safetyLabelInfo) } - private fun getAppMetadata(): PersistableBundle { - return if (isPlaceholderSafetyLabelDataEnabled()) { - placeholderMetadataBundle() - } else { - app.packageManager.getAppMetadata(packageName) - } - } - - private fun placeholderMetadataBundle(): PersistableBundle { - val approximateLocationBundle = - PersistableBundle().apply { putIntArray("purposes", (1..7).toList().toIntArray()) } - - val locationBundle = - PersistableBundle().apply { - putPersistableBundle( - DataTypeConstants.LOCATION_APPROX_LOCATION, approximateLocationBundle) - } - - val dataSharedBundle = - PersistableBundle().apply { - putPersistableBundle(DataCategoryConstants.CATEGORY_LOCATION, locationBundle) - } - - val dataLabelBundle = - PersistableBundle().apply { - putPersistableBundle(DataLabelConstants.DATA_USAGE_SHARED, dataSharedBundle) - } - - val safetyLabelBundle = PersistableBundle().apply { - putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION) - putPersistableBundle("data_labels", dataLabelBundle) - } - - return PersistableBundle().apply { - putLong(KEY_VERSION, INITIAL_METADATA_VERSION) - putPersistableBundle("safety_labels", safetyLabelBundle) - } - } - companion object : DataRepositoryForPackage<Pair<String, UserHandle>, SafetyLabelInfoLiveData>( ) { - private const val INITIAL_METADATA_VERSION = 1L - private const val INITIAL_SAFETY_LABELS_VERSION = 1L private val LOG_TAG = SafetyLabelInfoLiveData::class.java.simpleName override fun newValue(key: Pair<String, UserHandle>): SafetyLabelInfoLiveData { diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java index e97c6ef4b..8f73f6577 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java @@ -89,7 +89,7 @@ import java.util.Random; public class GrantPermissionsActivity extends SettingsActivity implements GrantPermissionsViewHandler.ResultListener { - private static final String LOG_TAG = "GrantPermissionsActivit"; + private static final String LOG_TAG = "GrantPermissionsActivity"; private static final String KEY_SESSION_ID = GrantPermissionsActivity.class.getName() + "_REQUEST_ID"; diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java index 007707363..9fad46648 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java @@ -73,7 +73,6 @@ import androidx.lifecycle.ViewModelProvider; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState; -import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo; import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs; import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler; import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel; @@ -87,12 +86,13 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.widget.ActionBarShadowController; +import kotlin.Pair; + import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; -import kotlin.Pair; - /** * Show and manage a single permission group for an app. * @@ -195,10 +195,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader getActivity().getApplication(), mPackageName, mPermGroupName, mUser, mSessionId); mViewModel = new ViewModelProvider(this, factory).get(AppPermissionViewModel.class); Handler delayHandler = new Handler(Looper.getMainLooper()); - if (KotlinUtils.INSTANCE.isPermissionRationaleEnabled()) { - mViewModel.getSafetyLabelInfoLiveData().observe(this, - this::showPermissionRationaleDialog); - } + mViewModel.getShowPermissionRationaleLiveData().observe(this, show -> { + showPermissionRationaleDialog(Optional.ofNullable(show).orElse(false)); + }); mViewModel.getButtonStateLiveData().observe(this, buttonState -> { if (mIsInitialLoad) { setRadioButtonsState(buttonState); @@ -295,11 +294,6 @@ public class AppPermissionFragment extends SettingsWithLargeHeader root.requireViewById(R.id.app_permission_rationale_container); mAppPermissionRationaleContent = root.requireViewById(R.id.app_permission_rationale_content); - if (!KotlinUtils.INSTANCE.isPermissionRationaleEnabled()) { - hidePermissionRationaleContainer(); - } else { - setPermissionRationaleContainer(root, context); - } getActivity().setTitle( getPreferenceManager().getContext().getString(R.string.app_permission_title, @@ -307,19 +301,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader return root; } - private void setPermissionRationaleContainer(View root, Context context) { - ((TextView) root.requireViewById(R.id.app_permission_rationale_message)).setText( - context.getString(R.string.app_permission_rationale_message)); - ((TextView) root.requireViewById(R.id.app_permission_rationale_title)).setText( - context.getString(R.string.app_location_permission_rationale_title)); - ((TextView) root.requireViewById(R.id.app_permission_rationale_subtitle)).setText( - context.getString(R.string.app_location_permission_rationale_subtitle)); - } - - private void showPermissionRationaleDialog(@Nullable SafetyLabelInfo safetyLabelInfo) { - if (safetyLabelInfo == null - || !mViewModel.shouldShowPermissionRationale(safetyLabelInfo, mPermGroupName)) { - hidePermissionRationaleContainer(); + private void showPermissionRationaleDialog(boolean showPermissionRationale) { + if (!showPermissionRationale) { + mAppPermissionRationaleContainer.setVisibility(View.GONE); } else { mAppPermissionRationaleContainer.setVisibility(View.VISIBLE); mAppPermissionRationaleContent.setOnClickListener((v) -> { @@ -328,10 +312,6 @@ public class AppPermissionFragment extends SettingsWithLargeHeader } } - private void hidePermissionRationaleContainer() { - mAppPermissionRationaleContainer.setVisibility(View.GONE); - } - private void setBottomLinkState(TextView view, String caller, String action) { if ((Objects.equals(caller, AppPermissionGroupsFragment.class.getName()) && action.equals(Intent.ACTION_MANAGE_APP_PERMISSIONS)) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt index ac20a7748..2e1744f54 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt @@ -60,7 +60,6 @@ import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveD import com.android.permissioncontroller.permission.data.get import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission -import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo import com.android.permissioncontroller.permission.service.PermissionChangeStorageImpl import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs @@ -78,10 +77,8 @@ import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleAct import com.android.permissioncontroller.permission.utils.KotlinUtils import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultPrecision import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled -import com.android.permissioncontroller.permission.utils.KotlinUtils.isPermissionRationaleEnabled import com.android.permissioncontroller.permission.utils.LocationUtils import com.android.permissioncontroller.permission.utils.PermissionMapping -import com.android.permissioncontroller.permission.utils.PermissionRationales import com.android.permissioncontroller.permission.utils.SafetyNetLogger import com.android.permissioncontroller.permission.utils.Utils import com.android.permissioncontroller.permission.utils.navigateSafe @@ -114,8 +111,6 @@ class AppPermissionViewModel( const val PHOTO_PICKER_REQUEST_CODE = 1 } - val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user] - interface ConfirmDialogShowingFragment { fun showConfirmDialog( changeRequest: ChangeRequest, @@ -184,6 +179,36 @@ class AppPermissionViewModel( val showAdminSupportLiveData = MutableLiveData<RestrictedLockUtils.EnforcedAdmin>() /** + * A livedata for determining the display state of safety label information + */ + val showPermissionRationaleLiveData = object : SmartUpdateMediatorLiveData<Boolean>() { + private val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user] + + init { + if (PermissionMapping.isSafetyLabelAwarePermission(permGroupName)) { + addSource(safetyLabelInfoLiveData) { update() } + } else { + value = false + } + } + + override fun onUpdate() { + if (safetyLabelInfoLiveData.isStale) { + return + } + + val safetyLabel = safetyLabelInfoLiveData.value?.safetyLabel + if (safetyLabel == null) { + value = false + return + } + + value = PermissionMapping.getSafetyLabelSharingPurposesForGroup( + safetyLabel, permGroupName).any() + } + } + + /** * A livedata which determines which detail string, if any, should be shown */ val fullStorageStateLiveData = object : SmartUpdateMediatorLiveData<FullStoragePackageState>() { @@ -549,14 +574,6 @@ class AppPermissionViewModel( return true } - fun shouldShowPermissionRationale( - safetyLabelInfo: SafetyLabelInfo, - groupName: String - ): Boolean { - return PermissionRationales.shouldShowPermissionRationale( - safetyLabelInfo.safetyLabel, groupName) - } - /** * Shows the Permission Rationale Dialog. For use with U+ only, otherwise no-op. * @@ -564,10 +581,6 @@ class AppPermissionViewModel( * @param groupName The name of the permission group whose fragment should be opened */ fun showPermissionRationaleActivity(activity: Activity, groupName: String) { - if (!isPermissionRationaleEnabled()) { - return - } - val intent = Intent(activity, PermissionRationaleActivity::class.java).apply { putExtra(Intent.EXTRA_PACKAGE_NAME, packageName) putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt index b82536dd5..01fd079c6 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt @@ -120,9 +120,7 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultP import com.android.permissioncontroller.permission.utils.KotlinUtils.grantBackgroundRuntimePermissions import com.android.permissioncontroller.permission.utils.KotlinUtils.grantForegroundRuntimePermissions import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled -import com.android.permissioncontroller.permission.utils.KotlinUtils.isPermissionRationaleEnabled import com.android.permissioncontroller.permission.utils.PermissionMapping -import com.android.permissioncontroller.permission.utils.PermissionRationales import com.android.permissioncontroller.permission.utils.SafetyNetLogger import com.android.permissioncontroller.permission.utils.Utils @@ -147,12 +145,16 @@ class GrantPermissionsViewModel( private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName private val user = Process.myUserHandle() private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user] - private val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user] + private val safetyLabelInfoLiveData = + if (requestedPermissions.any { PermissionMapping.isSafetyLabelAwarePermission(it) }) { + SafetyLabelInfoLiveData[packageName, user] + } else { + null + } private val dpm = app.getSystemService(DevicePolicyManager::class.java)!! private val permissionPolicy = dpm.getPermissionPolicy(null) private val permGroupsToSkip = mutableListOf<String>() private var groupStates = mutableMapOf<Pair<String, Boolean>, GroupState>() - private val permissionRationaleEnabled: Boolean by lazy { isPermissionRationaleEnabled() } private var autoGrantNotifier: AutoGrantPermissionsNotifier? = null private fun getAutoGrantNotifier(): AutoGrantPermissionsNotifier { @@ -161,7 +163,6 @@ class GrantPermissionsViewModel( } private lateinit var packageInfo: LightPackageInfo - private var safetyLabel: SafetyLabel? = null // All permissions that could possibly be affected by the provided requested permissions, before // filtering system fixed, auto grant, etc. @@ -198,12 +199,10 @@ class GrantPermissionsViewModel( private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName private val packagePermissionsLiveData = PackagePermissionsLiveData[packageName, user] - // TODO(b/260873483): only query safety label for supported permission groups. should only - // query location, but currently queries for all groups init { addSource(packagePermissionsLiveData) { onPackageLoaded() } addSource(packageInfoLiveData) { onPackageLoaded() } - if (permissionRationaleEnabled) { + if (safetyLabelInfoLiveData != null) { addSource(safetyLabelInfoLiveData) { onPackageLoaded() } } @@ -214,17 +213,10 @@ class GrantPermissionsViewModel( private fun onPackageLoaded() { if (packageInfoLiveData.isStale || packagePermissionsLiveData.isStale || - (permissionRationaleEnabled && safetyLabelInfoLiveData.isStale)) { + (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale)) { return } - safetyLabel = - if (permissionRationaleEnabled) { - safetyLabelInfoLiveData.value?.safetyLabel - } else { - null - } - val groups = packagePermissionsLiveData.value val pI = packageInfoLiveData.value if (groups == null || groups.isEmpty() || pI == null) { @@ -568,14 +560,15 @@ class GrantPermissionsViewModel( } } + val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel + requestInfos.add(RequestInfo( groupInfo, buttonVisibilities, locationVisibilities, message, detailMessage, - showPermissionRationale = shouldShowPermissionRationale( - safetyLabel, groupState))) + shouldShowPermissionRationale(safetyLabel, groupState))) } sortPermissionGroups(requestInfos) @@ -591,6 +584,19 @@ class GrantPermissionsViewModel( } } + private fun shouldShowPermissionRationale( + safetyLabel: SafetyLabel?, + groupState: GroupState + ): Boolean { + if (safetyLabel == null) { + return false + } + + val purposes = PermissionMapping.getSafetyLabelSharingPurposesForGroup(safetyLabel, + groupState.group.permGroupName) + return purposes.isNotEmpty() + } + fun sortPermissionGroups(requestInfos: MutableList<RequestInfo>) { requestInfos.sortWith { rhs, lhs -> val rhsHasOneTime = rhs.buttonVisibilities[ALLOW_ONE_TIME_BUTTON] @@ -607,14 +613,6 @@ class GrantPermissionsViewModel( } } - private fun shouldShowPermissionRationale( - safetyLabel: SafetyLabel?, - groupState: GroupState - ): Boolean { - return PermissionRationales.shouldShowPermissionRationale( - safetyLabel, groupState.group.permGroupName) - } - /** * Converts a list of LightAppPermGroups into a list of GroupStates */ diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt index 8de8de726..54d94f913 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt @@ -29,23 +29,18 @@ import android.util.Log import androidx.annotation.RequiresApi import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.android.permission.safetylabel.DataCategory -import com.android.permission.safetylabel.DataType -import com.android.permission.safetylabel.DataTypeConstants -import com.android.permission.safetylabel.SafetyLabel import com.android.permissioncontroller.Constants import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.data.SafetyLabelInfoLiveData import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData import com.android.permissioncontroller.permission.data.get -import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo.Companion.UNAVAILABLE import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity import com.android.permissioncontroller.permission.utils.KotlinUtils import com.android.permissioncontroller.permission.utils.KotlinUtils.getAppStoreIntent -import com.android.permissioncontroller.permission.utils.SafetyLabelPermissionMapping +import com.android.permissioncontroller.permission.utils.PermissionMapping import com.android.settingslib.HelpUtils /** @@ -90,7 +85,7 @@ class PermissionRationaleViewModel( data class PermissionRationaleInfo( val groupName: String, val installSourcePackageName: String?, - val installSourceLabel: CharSequence?, + val installSourceLabel: String?, val purposeSet: Set<Int> ) @@ -111,18 +106,15 @@ class PermissionRationaleViewModel( } val safetyLabelInfo = safetyLabelInfoLiveData.value - val safetyLabel = safetyLabelInfo?.safetyLabel - if (safetyLabelInfo == null || - safetyLabelInfo == UNAVAILABLE || - safetyLabel == null) { + if (safetyLabelInfo?.safetyLabel == null) { Log.e(LOG_TAG, "Safety label for $packageName not found") value = null return } val installSourcePackageName = safetyLabelInfo.installSourcePackageName - val installSourceLabel: CharSequence? = + val installSourceLabel: String? = installSourcePackageName?.let { KotlinUtils.getPackageLabel(app, it, Process.myUserHandle()) } @@ -132,36 +124,8 @@ class PermissionRationaleViewModel( permissionGroupName, installSourcePackageName, installSourceLabel, - getSafetyLabelSharingPurposesForGroup(safetyLabel, permissionGroupName)) - } - - private fun getSafetyLabelSharingPurposesForGroup( - safetyLabel: SafetyLabel, - groupName: String - ): Set<Int> { - val purposeSet = mutableSetOf<Int>() - val categoriesForPermission: List<String> = - SafetyLabelPermissionMapping.getCategoriesForPermissionGroup(groupName) - categoriesForPermission.forEach categoryLoop@{ category -> - val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category] - if (dataCategory == null) { - // Continue to next - return@categoryLoop - } - val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category) - typesForCategory.forEach typeLoop@{ type -> - val dataType: DataType? = dataCategory.dataTypes[type] - if (dataType == null) { - // Continue to next - return@typeLoop - } - if (dataType.purposeSet.isNotEmpty()) { - purposeSet.addAll(dataType.purposeSet) - } - } - } - - return purposeSet + PermissionMapping.getSafetyLabelSharingPurposesForGroup( + safetyLabelInfo.safetyLabel, permissionGroupName)) } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt index 3fde87108..45a7fb02e 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt @@ -21,7 +21,13 @@ import android.content.pm.PackageManager import android.content.pm.PermissionInfo import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP import android.util.Log + import com.android.modules.utils.build.SdkLevel +import com.android.permission.safetylabel.DataCategory +import com.android.permission.safetylabel.DataCategoryConstants +import com.android.permission.safetylabel.DataType +import com.android.permission.safetylabel.DataTypeConstants +import com.android.permission.safetylabel.SafetyLabel /** * This file contains the canonical mapping of permission to permission group, used in the @@ -31,6 +37,9 @@ object PermissionMapping { private val LOG_TAG = "PermissionMapping" + private val PERMISSION_GROUPS_TO_DATA_CATEGORIES: Map<String, List<String>> = mapOf( + Manifest.permission_group.LOCATION to listOf(DataCategoryConstants.CATEGORY_LOCATION)) + @JvmField val SENSOR_DATA_PERMISSIONS: List<String> = listOf( @@ -326,4 +335,64 @@ object PermissionMapping { fun isHealthPermission(permissionName: String): Boolean { return HEALTH_PERMISSIONS_SET.contains(permissionName) } + + /** + * Get the sharing purposes for a SafetyLabel related to a specific permission group. + */ + @JvmStatic + fun getSafetyLabelSharingPurposesForGroup( + safetyLabel: SafetyLabel, + groupName: String + ): Set<Int> { + val purposeSet = mutableSetOf<Int>() + val categoriesForPermission = getDataCategoriesForPermissionGroup(groupName) + categoriesForPermission.forEach categoryLoop@{ category -> + val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category] + if (dataCategory == null) { + // Continue to next + return@categoryLoop + } + val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category) + typesForCategory.forEach typeLoop@{ type -> + val dataType: DataType? = dataCategory.dataTypes[type] + if (dataType == null) { + // Continue to next + return@typeLoop + } + if (dataType.purposeSet.isNotEmpty()) { + purposeSet.addAll(dataType.purposeSet) + } + } + } + + return purposeSet + } + + /** + * Get the SafetyLabel categories pertaining to a specified permission group. + * + * @return The categories, or an empty list if the group does not have a supported mapping + * to safety label category + */ + fun getDataCategoriesForPermissionGroup(permissionGroupName: String): List<String> { + return if (isSafetyLabelAwarePermission(permissionGroupName)) { + PERMISSION_GROUPS_TO_DATA_CATEGORIES[permissionGroupName] ?: emptyList() + } else { + emptyList() + } + } + + /** + * Whether this permission group maps to a SafetyLabel data category. + * + * @param permissionGroupName the permission group name + */ + @JvmStatic + fun isSafetyLabelAwarePermission(permissionGroupName: String): Boolean { + if (!KotlinUtils.isPermissionRationaleEnabled()) { + return false + } + + return PERMISSION_GROUPS_TO_DATA_CATEGORIES.containsKey(permissionGroupName) + } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionRationales.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionRationales.kt deleted file mode 100644 index ede87e84f..000000000 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionRationales.kt +++ /dev/null @@ -1,64 +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.permissioncontroller.permission.utils - -import com.android.permission.safetylabel.DataCategory -import com.android.permission.safetylabel.DataType -import com.android.permission.safetylabel.DataTypeConstants -import com.android.permission.safetylabel.SafetyLabel - -/** - * A set of util functions used for permission rationale dialog. - */ -object PermissionRationales { - - /** - * Returns if the permission rationale dialog should be shown. - * @param safetyLabel the [SafetyLabel] bundle provided - * @param groupName the permission group name - * @return true if the permission dialog should be shown, otherwise false. - */ - fun shouldShowPermissionRationale( - safetyLabel: SafetyLabel?, - groupName: String - ): Boolean { - if (safetyLabel == null || safetyLabel.dataLabel.dataShared.isEmpty()) { - return false - } - val categoriesForPermission: List<String> = - SafetyLabelPermissionMapping.getCategoriesForPermissionGroup(groupName) - categoriesForPermission.forEach categoryLoop@{ category -> - val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category] - if (dataCategory == null) { - // Continue to next - return@categoryLoop - } - val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category) - typesForCategory.forEach typeLoop@{ type -> - val dataType: DataType? = dataCategory.dataTypes[type] - if (dataType == null) { - // Continue to next - return@typeLoop - } - if (dataType.purposeSet.isNotEmpty()) { - return true - } - } - } - return false - } -}
\ No newline at end of file diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyLabelPermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyLabelPermissionMapping.kt deleted file mode 100644 index 5fd852bb6..000000000 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyLabelPermissionMapping.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2022 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.permissioncontroller.permission.utils - -import android.Manifest -import com.android.permission.safetylabel.DataCategoryConstants - -/** - * This file contains the canonical mapping of permission and permission group to Safety Label - * categories and types used in the Permission settings screens and grant dialog. It also includes - * methods related to that mapping. - */ -object SafetyLabelPermissionMapping { - - /** - * Get the Safety Label categories pertaining to a specified permission group. - * - * @param groupName the permission group name - * - * @return The categories or an empty list if the group does not have supported and mapped group - * to safety label category - */ - fun getCategoriesForPermissionGroup(groupName: String): List<String> { - return if (groupName == Manifest.permission_group.LOCATION) { - listOf(DataCategoryConstants.CATEGORY_LOCATION) - } else { - emptyList() - } - } -} diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java b/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java index 564d5479f..676cfa6d7 100644 --- a/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java +++ b/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java @@ -32,7 +32,10 @@ import java.util.Map; * {@link DataCategory} */ public class DataLabel { - @VisibleForTesting static final String KEY_DATA_LABEL = "data_labels"; + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + static final String KEY_DATA_LABEL = "data_labels"; + private final Map<String, DataCategory> mDataCollected; private final Map<String, DataCategory> mDataShared; diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataType.java b/SafetyLabel/java/com/android/permission/safetylabel/DataType.java index 68770f823..3350a5942 100644 --- a/SafetyLabel/java/com/android/permission/safetylabel/DataType.java +++ b/SafetyLabel/java/com/android/permission/safetylabel/DataType.java @@ -35,7 +35,10 @@ import java.util.Set; * metadata related to the data usage purpose. */ public class DataType { - @VisibleForTesting static final String KEY_PURPOSES = "purposes"; + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + static final String KEY_PURPOSES = "purposes"; + @VisibleForTesting static final String KEY_IS_COLLECTION_OPTIONAL = "is_collection_optional"; @VisibleForTesting static final String KEY_EPHEMERAL = "ephemeral"; diff --git a/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java b/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java index 3eb8767b9..0ada11719 100644 --- a/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java +++ b/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java @@ -28,6 +28,10 @@ import java.util.Locale; /** Safety Label representation containing zero or more {@link DataCategory} for data shared */ public class SafetyLabel { private static final String TAG = "SafetyLabel"; + + private static final long INITIAL_METADATA_VERSION = 1L; + private static final long INITIAL_SAFETY_LABELS_VERSION = 1L; + @VisibleForTesting static final String KEY_SAFETY_LABEL = "safety_labels"; public static final String KEY_VERSION = "version"; private final DataLabel mDataLabel; @@ -69,6 +73,44 @@ public class SafetyLabel { return new SafetyLabel(dataLabel); } + /** + * Create a placeholder SafetyLabel for use for testing. + * This is accessible through device configs. + */ + @NonNull + public static SafetyLabel getPlaceholderSafetyLabel() { + return getSafetyLabelFromMetadata(getPlaceholderMetadataBundle()); + } + + @NonNull + private static PersistableBundle getPlaceholderMetadataBundle() { + PersistableBundle approximateLocationBundle = new PersistableBundle(); + approximateLocationBundle.putIntArray(DataType.KEY_PURPOSES, + new int[] { 1, 2, 3, 4, 5, 6, 7 }); + + PersistableBundle locationBundle = new PersistableBundle(); + locationBundle.putPersistableBundle(DataTypeConstants.LOCATION_APPROX_LOCATION, + approximateLocationBundle); + + PersistableBundle dataSharedBundle = new PersistableBundle(); + dataSharedBundle.putPersistableBundle(DataCategoryConstants.CATEGORY_LOCATION, + locationBundle); + + PersistableBundle dataLabelBundle = new PersistableBundle(); + dataLabelBundle.putPersistableBundle(DataLabelConstants.DATA_USAGE_SHARED, + dataSharedBundle); + + PersistableBundle safetyLabelBundle = new PersistableBundle(); + safetyLabelBundle.putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION); + safetyLabelBundle.putPersistableBundle(DataLabel.KEY_DATA_LABEL, dataLabelBundle); + + PersistableBundle metadataBundle = new PersistableBundle(); + metadataBundle.putLong(KEY_VERSION, INITIAL_METADATA_VERSION); + metadataBundle.putPersistableBundle(KEY_SAFETY_LABEL, safetyLabelBundle); + + return metadataBundle; + } + /** Returns the data label for the safety label */ @NonNull public DataLabel getDataLabel() { |