From 7f13dcaadf1bf818dbfcab55abfa2709a5acd6d6 Mon Sep 17 00:00:00 2001 From: Ganesh Olekar Date: Thu, 17 Feb 2022 19:44:39 +0000 Subject: [PATCH] Location provider check for subattribution Bug: 200280741 Test: atest com.android.systemui.privacy.PrivacyDialogTest Change-Id: I7240db08025d801eb537234ca95aeb17c3f302f2 Merged-In: I7240db08025d801eb537234ca95aeb17c3f302f2 --- .../permission/PermissionUsageHelper.java | 15 ++- .../privacy/PrivacyDialogController.kt | 31 ++++--- .../privacy/PrivacyDialogControllerTest.kt | 92 +++++++++++++++++++ 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index 0b57842cde112..4ed939c48bd75 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -47,6 +47,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.icu.text.ListFormatter; +import android.location.LocationManager; import android.media.AudioManager; import android.os.Process; import android.os.UserHandle; @@ -411,10 +412,13 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis } /** - * Returns true if the app supports subattribution. + * Returns true if the app satisfies subattribution policies and supports it */ private boolean isSubattributionSupported(String packageName, int uid) { try { + if (!isLocationProvider(packageName)) { + return false; + } PackageManager userPkgManager = getUserContext(UserHandle.getUserHandleForUid(uid)).getPackageManager(); ApplicationInfo appInfo = userPkgManager.getApplicationInfoAsUser(packageName, @@ -429,6 +433,15 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis } } + /** + * @param packageName + * @return If the package is location provider + */ + private boolean isLocationProvider(String packageName) { + return Objects.requireNonNull( + mContext.getSystemService(LocationManager.class)).isProviderPackage(packageName); + } + /** * Get the raw usages from the system, and then parse out the ones that are not recent enough, * determine which permission group each belongs in, and removes duplicates (if the same app diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt index 61071235db0bd..8147877a8a29b 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt @@ -150,24 +150,27 @@ class PrivacyDialogController( packageName: String, userId: Int, permGroupName: CharSequence, - attributionTag: CharSequence? + attributionTag: CharSequence?, + isAttributionSupported: Boolean ): Intent { lateinit var intent: Intent - if (attributionTag != null) { + if (attributionTag != null && isAttributionSupported) { intent = Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE) intent.setPackage(packageName) intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName.toString()) intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, arrayOf(attributionTag.toString())) intent.putExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, true) val resolveInfo = packageManager.resolveActivity( - intent, PackageManager.ResolveInfoFlags.of(0)) - ?: return getDefaultManageAppPermissionsIntent(packageName, userId) - intent.component = ComponentName(packageName, resolveInfo.activityInfo.name) - return intent - } else { - return getDefaultManageAppPermissionsIntent(packageName, userId) + intent, PackageManager.ResolveInfoFlags.of(0)) + if (resolveInfo != null && resolveInfo.activityInfo != null && + resolveInfo.activityInfo.permission == + android.Manifest.permission.START_VIEW_PERMISSION_USAGE) { + intent.component = ComponentName(packageName, resolveInfo.activityInfo.name) + return intent + } } + return getDefaultManageAppPermissionsIntent(packageName, userId) } fun getDefaultManageAppPermissionsIntent(packageName: String, userId: Int): Intent { @@ -226,9 +229,15 @@ class PrivacyDialogController( userInfo?.isManagedProfile ?: false, it.isPhoneCall, it.permissionGroupName, - getManagePermissionIntent(it.packageName, userId, - it.permissionGroupName, - it.attributionTag) + getManagePermissionIntent( + it.packageName, + userId, + it.permissionGroupName, + it.attributionTag, + // attributionLabel is set only when subattribution policies + // are supported and satisfied + it.attributionLabel != null + ) ) } } else { diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt index 350822691121a..38b448fb362c2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt @@ -19,8 +19,11 @@ package com.android.systemui.privacy import android.app.ActivityManager import android.content.Context import android.content.Intent +import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager +import android.content.pm.PackageManager.ResolveInfoFlags +import android.content.pm.ResolveInfo import android.content.pm.UserInfo import android.os.Process.SYSTEM_UID import android.os.UserHandle @@ -648,6 +651,77 @@ class PrivacyDialogControllerTest : SysuiTestCase() { } } + @Test + fun testCorrectIntentSubAttribution() { + val usage = createMockPermGroupUsage( + attributionTag = TEST_ATTRIBUTION_TAG, + attributionLabel = "TEST_LABEL" + ) + + val activityInfo = createMockActivityInfo() + val resolveInfo = createMockResolveInfo(activityInfo) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + `when`(packageManager.resolveActivity(any(), any())) + .thenAnswer { resolveInfo } + controller.showDialog(context) + exhaustExecutors() + + dialogProvider.list?.let { list -> + val navigationIntent = list.get(0).navigationIntent!! + assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE) + assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME)) + .isEqualTo(PERM_CAMERA) + assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS)) + .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString())) + assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false)) + .isTrue() + } + } + + @Test + fun testDefaultIntentOnMissingAttributionLabel() { + val usage = createMockPermGroupUsage( + attributionTag = TEST_ATTRIBUTION_TAG + ) + + val activityInfo = createMockActivityInfo() + val resolveInfo = createMockResolveInfo(activityInfo) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + `when`(packageManager.resolveActivity(any(), any())) + .thenAnswer { resolveInfo } + controller.showDialog(context) + exhaustExecutors() + + dialogProvider.list?.let { list -> + assertThat(isIntentEqual(list.get(0).navigationIntent!!, + controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID))) + .isTrue() + } + } + + @Test + fun testDefaultIntentOnIncorrectPermission() { + val usage = createMockPermGroupUsage( + attributionTag = TEST_ATTRIBUTION_TAG + ) + + val activityInfo = createMockActivityInfo( + permission = "INCORRECT_PERMISSION" + ) + val resolveInfo = createMockResolveInfo(activityInfo) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + `when`(packageManager.resolveActivity(any(), any())) + .thenAnswer { resolveInfo } + controller.showDialog(context) + exhaustExecutors() + + dialogProvider.list?.let { list -> + assertThat(isIntentEqual(list.get(0).navigationIntent!!, + controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID))) + .isTrue() + } + } + private fun exhaustExecutors() { FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor) } @@ -680,6 +754,24 @@ class PrivacyDialogControllerTest : SysuiTestCase() { return user * UserHandle.PER_USER_RANGE + nextUid++ } + private fun createMockResolveInfo( + activityInfo: ActivityInfo? = null + ): ResolveInfo { + val resolveInfo = mock(ResolveInfo::class.java) + resolveInfo.activityInfo = activityInfo + return resolveInfo + } + + private fun createMockActivityInfo( + permission: String = android.Manifest.permission.START_VIEW_PERMISSION_USAGE, + className: String = "TEST_CLASS_NAME" + ): ActivityInfo { + val activityInfo = mock(ActivityInfo::class.java) + activityInfo.permission = permission + activityInfo.name = className + return activityInfo + } + private fun createMockPermGroupUsage( packageName: String = TEST_PACKAGE_NAME, uid: Int = generateUidForUser(USER_ID),