Loading services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +1 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; Loading Loading @@ -148,7 +147,7 @@ public abstract class SoftRestrictedPermissionPolicy { pkg.hasPreserveLegacyExternalStorage(); targetSDK = getMinimumTargetSDK(context, appInfo, user); shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; shouldApplyRestriction = !isWhiteListed; isForcedScopedStorage = sForcedScopedStorageAppWhitelist .contains(appInfo.packageName); } else { Loading services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +67 −17 Original line number Diff line number Diff line Loading @@ -227,23 +227,57 @@ class AppIdPermissionPolicy : SchemePolicy() { if (isRequestedBySystemPackage) { return@forEach } updatePermissionExemptFlags( appId, userId, permission, PermissionFlags.UPGRADE_EXEMPT, 0 ) } } fun MutateStateScope.updatePermissionExemptFlags( appId: Int, userId: Int, permission: Permission, exemptFlagMask: Int, exemptFlagValues: Int ) { val permissionName = permission.name val oldFlags = getPermissionFlags(appId, userId, permissionName) var newFlags = oldFlags andInv PermissionFlags.UPGRADE_EXEMPT var newFlags = (oldFlags andInv exemptFlagMask) or (exemptFlagValues and exemptFlagMask) if (oldFlags == newFlags) { return } val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT) newFlags = if (permission.isHardRestricted && !isExempt) { newFlags or PermissionFlags.RESTRICTION_REVOKED newFlags = newFlags or PermissionFlags.RESTRICTION_REVOKED // If the permission was policy fixed as granted but it is no longer on any of the // allowlists we need to clear the policy fixed flag as allowlisting trumps policy i.e. // policy cannot grant a non grantable permission. if (PermissionFlags.isPermissionGranted(oldFlags)) { newFlags = newFlags andInv PermissionFlags.POLICY_FIXED } } else { newFlags andInv PermissionFlags.RESTRICTION_REVOKED newFlags = newFlags andInv PermissionFlags.RESTRICTION_REVOKED } newFlags = if (permission.isSoftRestricted && !isExempt) { if ( permission.isSoftRestricted && !isExempt && !anyPackageInAppId(appId) { permissionName in it.androidPackage!!.requestedPermissions && isSoftRestrictedPermissionExemptForPackage(it, permissionName) } ) { newFlags or PermissionFlags.SOFT_RESTRICTED } else { newFlags andInv PermissionFlags.SOFT_RESTRICTED } setPermissionFlags(appId, userId, permissionName, newFlags) if (oldFlags == newFlags) { return } setPermissionFlags(appId, userId, permissionName, newFlags) } override fun MutateStateScope.onPackageUninstalled( Loading Loading @@ -1118,7 +1152,12 @@ class AppIdPermissionPolicy : SchemePolicy() { newFlags andInv PermissionFlags.RESTRICTION_REVOKED } newFlags = if (permission.isSoftRestricted && !isExempt) { if ( permission.isSoftRestricted && !isExempt && !requestingPackageStates.anyIndexed { _, it -> isSoftRestrictedPermissionExemptForPackage(it, permissionName) } ) { newFlags or PermissionFlags.SOFT_RESTRICTED } else { newFlags andInv PermissionFlags.SOFT_RESTRICTED Loading Loading @@ -1398,6 +1437,17 @@ class AppIdPermissionPolicy : SchemePolicy() { } } // See also SoftRestrictedPermissionPolicy.mayGrantPermission() private fun isSoftRestrictedPermissionExemptForPackage( packageState: PackageState, permissionName: String ): Boolean = when (permissionName) { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE -> packageState.androidPackage!!.targetSdkVersion >= Build.VERSION_CODES.Q else -> false } private inline fun MutateStateScope.anyPackageInAppId( appId: Int, state: AccessState = newState, Loading services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt +12 −3 Original line number Diff line number Diff line Loading @@ -346,9 +346,18 @@ object PermissionFlags { return flags.hasBits(RUNTIME_GRANTED) } fun isAppOpGranted(flags: Int): Boolean = isPermissionGranted(flags) && !flags.hasBits(RESTRICTION_REVOKED) && !flags.hasBits(APP_OP_REVOKED) fun isAppOpGranted(flags: Int): Boolean { if (!isPermissionGranted(flags)) { return false } if (flags.hasAnyBit(MASK_RESTRICTED)) { return false } if (flags.hasBits(APP_OP_REVOKED)) { return false } return true } fun toApiFlags(flags: Int): Int { var apiFlags = 0 Loading services/permission/java/com/android/server/permission/access/permission/PermissionService.kt +19 −96 Original line number Diff line number Diff line Loading @@ -88,7 +88,6 @@ import com.android.server.pm.PackageInstallerService import com.android.server.pm.PackageManagerLocal import com.android.server.pm.UserManagerInternal import com.android.server.pm.UserManagerService import com.android.server.pm.parsing.pkg.AndroidPackageUtils import com.android.server.pm.permission.LegacyPermission import com.android.server.pm.permission.LegacyPermissionSettings import com.android.server.pm.permission.LegacyPermissionState Loading @@ -97,7 +96,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInterface import com.android.server.pm.permission.PermissionManagerServiceInternal import com.android.server.pm.pkg.AndroidPackage import com.android.server.pm.pkg.PackageState import com.android.server.policy.SoftRestrictedPermissionPolicy import java.io.FileDescriptor import java.io.PrintWriter import java.util.concurrent.CompletableFuture Loading Loading @@ -1006,16 +1004,6 @@ class PermissionService(private val service: AccessCheckingService) : } if (isGranted && oldFlags.hasBits(PermissionFlags.SOFT_RESTRICTED)) { // TODO: Refactor SoftRestrictedPermissionPolicy. val softRestrictedPermissionPolicy = SoftRestrictedPermissionPolicy.forPermission( context, AndroidPackageUtils.generateAppInfoWithoutState(androidPackage), androidPackage, UserHandle.of(userId), permissionName ) if (!softRestrictedPermissionPolicy.mayGrantPermission()) { if (reportError) { Slog.e( LOG_TAG, Loading @@ -1025,7 +1013,6 @@ class PermissionService(private val service: AccessCheckingService) : } return } } val newFlags = PermissionFlags.updateRuntimePermissionGranted(oldFlags, isGranted) if (oldFlags == newFlags) { Loading Loading @@ -1850,10 +1837,19 @@ class PermissionService(private val service: AccessCheckingService) : allowlistedFlags: Int, userId: Int ) { var exemptMask = 0 if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) { exemptMask = exemptMask or PermissionFlags.SYSTEM_EXEMPT } if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE)) { exemptMask = exemptMask or PermissionFlags.UPGRADE_EXEMPT } if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) { exemptMask = exemptMask or PermissionFlags.INSTALLER_EXEMPT } service.mutateState { with(policy) { val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState val permissions = getPermissions() androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission -> val permission = permissions[requestedPermission] Loading @@ -1861,81 +1857,8 @@ class PermissionService(private val service: AccessCheckingService) : return@forEachIndexed } val oldFlags = permissionsFlags[requestedPermission] ?: 0 val wasGranted = PermissionFlags.isPermissionGranted(oldFlags) var newFlags = oldFlags var mask = 0 var allowlistFlagsCopy = allowlistedFlags while (allowlistFlagsCopy != 0) { val flag = 1 shl allowlistFlagsCopy.countTrailingZeroBits() allowlistFlagsCopy = allowlistFlagsCopy and flag.inv() when (flag) { PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM -> { mask = mask or PermissionFlags.SYSTEM_EXEMPT newFlags = if (permissionNames.contains(requestedPermission)) { newFlags or PermissionFlags.SYSTEM_EXEMPT } else { newFlags andInv PermissionFlags.SYSTEM_EXEMPT } } PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE -> { mask = mask or PermissionFlags.UPGRADE_EXEMPT newFlags = if (permissionNames.contains(requestedPermission)) { newFlags or PermissionFlags.UPGRADE_EXEMPT } else { newFlags andInv PermissionFlags.UPGRADE_EXEMPT } } PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER -> { mask = mask or PermissionFlags.INSTALLER_EXEMPT newFlags = if (permissionNames.contains(requestedPermission)) { newFlags or PermissionFlags.INSTALLER_EXEMPT } else { newFlags andInv PermissionFlags.INSTALLER_EXEMPT } } } } if (oldFlags == newFlags) { return@forEachIndexed } val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT) // If the permission is policy fixed as granted but it is no longer // on any of the allowlists we need to clear the policy fixed flag // as allowlisting trumps policy i.e. policy cannot grant a non // grantable permission. if (oldFlags.hasBits(PermissionFlags.POLICY_FIXED)) { if (!isExempt && wasGranted) { mask = mask or PermissionFlags.POLICY_FIXED newFlags = newFlags andInv PermissionFlags.POLICY_FIXED } } newFlags = if (permission.isHardRestricted && !isExempt) { newFlags or PermissionFlags.RESTRICTION_REVOKED } else { newFlags andInv PermissionFlags.RESTRICTION_REVOKED } newFlags = if (permission.isSoftRestricted && !isExempt) { newFlags or PermissionFlags.SOFT_RESTRICTED } else { newFlags andInv PermissionFlags.SOFT_RESTRICTED } mask = mask or PermissionFlags.RESTRICTION_REVOKED or PermissionFlags.SOFT_RESTRICTED updatePermissionFlags(appId, userId, requestedPermission, mask, newFlags) var exemptFlags = if (requestedPermission in permissionNames) exemptMask else 0 updatePermissionExemptFlags(appId, userId, permission, exemptMask, exemptFlags) } } } Loading services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt +0 −18 Original line number Diff line number Diff line Loading @@ -233,24 +233,6 @@ class AppIdPermissionPolicyTest : BasePermissionPolicyTest() { .isEqualTo(expectedNewFlags) } @Test fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() { val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.INSTALLER_EXEMPT testOnPackageInstalled( oldFlags, permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED ) {} val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) val expectedNewFlags = PermissionFlags.INSTALLER_EXEMPT assertWithMessage( "After onPackageInstalled() is called for a non-system app that requests a runtime" + " soft restricted permission that is exempted. The actual permission flags" + " $actualFlags should match the expected flags $expectedNewFlags" ) .that(actualFlags) .isEqualTo(expectedNewFlags) } private fun testOnPackageInstalled( oldFlags: Int, permissionInfoFlags: Int = 0, Loading Loading
services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +1 −2 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; Loading Loading @@ -148,7 +147,7 @@ public abstract class SoftRestrictedPermissionPolicy { pkg.hasPreserveLegacyExternalStorage(); targetSDK = getMinimumTargetSDK(context, appInfo, user); shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; shouldApplyRestriction = !isWhiteListed; isForcedScopedStorage = sForcedScopedStorageAppWhitelist .contains(appInfo.packageName); } else { Loading
services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +67 −17 Original line number Diff line number Diff line Loading @@ -227,23 +227,57 @@ class AppIdPermissionPolicy : SchemePolicy() { if (isRequestedBySystemPackage) { return@forEach } updatePermissionExemptFlags( appId, userId, permission, PermissionFlags.UPGRADE_EXEMPT, 0 ) } } fun MutateStateScope.updatePermissionExemptFlags( appId: Int, userId: Int, permission: Permission, exemptFlagMask: Int, exemptFlagValues: Int ) { val permissionName = permission.name val oldFlags = getPermissionFlags(appId, userId, permissionName) var newFlags = oldFlags andInv PermissionFlags.UPGRADE_EXEMPT var newFlags = (oldFlags andInv exemptFlagMask) or (exemptFlagValues and exemptFlagMask) if (oldFlags == newFlags) { return } val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT) newFlags = if (permission.isHardRestricted && !isExempt) { newFlags or PermissionFlags.RESTRICTION_REVOKED newFlags = newFlags or PermissionFlags.RESTRICTION_REVOKED // If the permission was policy fixed as granted but it is no longer on any of the // allowlists we need to clear the policy fixed flag as allowlisting trumps policy i.e. // policy cannot grant a non grantable permission. if (PermissionFlags.isPermissionGranted(oldFlags)) { newFlags = newFlags andInv PermissionFlags.POLICY_FIXED } } else { newFlags andInv PermissionFlags.RESTRICTION_REVOKED newFlags = newFlags andInv PermissionFlags.RESTRICTION_REVOKED } newFlags = if (permission.isSoftRestricted && !isExempt) { if ( permission.isSoftRestricted && !isExempt && !anyPackageInAppId(appId) { permissionName in it.androidPackage!!.requestedPermissions && isSoftRestrictedPermissionExemptForPackage(it, permissionName) } ) { newFlags or PermissionFlags.SOFT_RESTRICTED } else { newFlags andInv PermissionFlags.SOFT_RESTRICTED } setPermissionFlags(appId, userId, permissionName, newFlags) if (oldFlags == newFlags) { return } setPermissionFlags(appId, userId, permissionName, newFlags) } override fun MutateStateScope.onPackageUninstalled( Loading Loading @@ -1118,7 +1152,12 @@ class AppIdPermissionPolicy : SchemePolicy() { newFlags andInv PermissionFlags.RESTRICTION_REVOKED } newFlags = if (permission.isSoftRestricted && !isExempt) { if ( permission.isSoftRestricted && !isExempt && !requestingPackageStates.anyIndexed { _, it -> isSoftRestrictedPermissionExemptForPackage(it, permissionName) } ) { newFlags or PermissionFlags.SOFT_RESTRICTED } else { newFlags andInv PermissionFlags.SOFT_RESTRICTED Loading Loading @@ -1398,6 +1437,17 @@ class AppIdPermissionPolicy : SchemePolicy() { } } // See also SoftRestrictedPermissionPolicy.mayGrantPermission() private fun isSoftRestrictedPermissionExemptForPackage( packageState: PackageState, permissionName: String ): Boolean = when (permissionName) { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE -> packageState.androidPackage!!.targetSdkVersion >= Build.VERSION_CODES.Q else -> false } private inline fun MutateStateScope.anyPackageInAppId( appId: Int, state: AccessState = newState, Loading
services/permission/java/com/android/server/permission/access/permission/PermissionFlags.kt +12 −3 Original line number Diff line number Diff line Loading @@ -346,9 +346,18 @@ object PermissionFlags { return flags.hasBits(RUNTIME_GRANTED) } fun isAppOpGranted(flags: Int): Boolean = isPermissionGranted(flags) && !flags.hasBits(RESTRICTION_REVOKED) && !flags.hasBits(APP_OP_REVOKED) fun isAppOpGranted(flags: Int): Boolean { if (!isPermissionGranted(flags)) { return false } if (flags.hasAnyBit(MASK_RESTRICTED)) { return false } if (flags.hasBits(APP_OP_REVOKED)) { return false } return true } fun toApiFlags(flags: Int): Int { var apiFlags = 0 Loading
services/permission/java/com/android/server/permission/access/permission/PermissionService.kt +19 −96 Original line number Diff line number Diff line Loading @@ -88,7 +88,6 @@ import com.android.server.pm.PackageInstallerService import com.android.server.pm.PackageManagerLocal import com.android.server.pm.UserManagerInternal import com.android.server.pm.UserManagerService import com.android.server.pm.parsing.pkg.AndroidPackageUtils import com.android.server.pm.permission.LegacyPermission import com.android.server.pm.permission.LegacyPermissionSettings import com.android.server.pm.permission.LegacyPermissionState Loading @@ -97,7 +96,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInterface import com.android.server.pm.permission.PermissionManagerServiceInternal import com.android.server.pm.pkg.AndroidPackage import com.android.server.pm.pkg.PackageState import com.android.server.policy.SoftRestrictedPermissionPolicy import java.io.FileDescriptor import java.io.PrintWriter import java.util.concurrent.CompletableFuture Loading Loading @@ -1006,16 +1004,6 @@ class PermissionService(private val service: AccessCheckingService) : } if (isGranted && oldFlags.hasBits(PermissionFlags.SOFT_RESTRICTED)) { // TODO: Refactor SoftRestrictedPermissionPolicy. val softRestrictedPermissionPolicy = SoftRestrictedPermissionPolicy.forPermission( context, AndroidPackageUtils.generateAppInfoWithoutState(androidPackage), androidPackage, UserHandle.of(userId), permissionName ) if (!softRestrictedPermissionPolicy.mayGrantPermission()) { if (reportError) { Slog.e( LOG_TAG, Loading @@ -1025,7 +1013,6 @@ class PermissionService(private val service: AccessCheckingService) : } return } } val newFlags = PermissionFlags.updateRuntimePermissionGranted(oldFlags, isGranted) if (oldFlags == newFlags) { Loading Loading @@ -1850,10 +1837,19 @@ class PermissionService(private val service: AccessCheckingService) : allowlistedFlags: Int, userId: Int ) { var exemptMask = 0 if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) { exemptMask = exemptMask or PermissionFlags.SYSTEM_EXEMPT } if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE)) { exemptMask = exemptMask or PermissionFlags.UPGRADE_EXEMPT } if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) { exemptMask = exemptMask or PermissionFlags.INSTALLER_EXEMPT } service.mutateState { with(policy) { val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState val permissions = getPermissions() androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission -> val permission = permissions[requestedPermission] Loading @@ -1861,81 +1857,8 @@ class PermissionService(private val service: AccessCheckingService) : return@forEachIndexed } val oldFlags = permissionsFlags[requestedPermission] ?: 0 val wasGranted = PermissionFlags.isPermissionGranted(oldFlags) var newFlags = oldFlags var mask = 0 var allowlistFlagsCopy = allowlistedFlags while (allowlistFlagsCopy != 0) { val flag = 1 shl allowlistFlagsCopy.countTrailingZeroBits() allowlistFlagsCopy = allowlistFlagsCopy and flag.inv() when (flag) { PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM -> { mask = mask or PermissionFlags.SYSTEM_EXEMPT newFlags = if (permissionNames.contains(requestedPermission)) { newFlags or PermissionFlags.SYSTEM_EXEMPT } else { newFlags andInv PermissionFlags.SYSTEM_EXEMPT } } PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE -> { mask = mask or PermissionFlags.UPGRADE_EXEMPT newFlags = if (permissionNames.contains(requestedPermission)) { newFlags or PermissionFlags.UPGRADE_EXEMPT } else { newFlags andInv PermissionFlags.UPGRADE_EXEMPT } } PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER -> { mask = mask or PermissionFlags.INSTALLER_EXEMPT newFlags = if (permissionNames.contains(requestedPermission)) { newFlags or PermissionFlags.INSTALLER_EXEMPT } else { newFlags andInv PermissionFlags.INSTALLER_EXEMPT } } } } if (oldFlags == newFlags) { return@forEachIndexed } val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT) // If the permission is policy fixed as granted but it is no longer // on any of the allowlists we need to clear the policy fixed flag // as allowlisting trumps policy i.e. policy cannot grant a non // grantable permission. if (oldFlags.hasBits(PermissionFlags.POLICY_FIXED)) { if (!isExempt && wasGranted) { mask = mask or PermissionFlags.POLICY_FIXED newFlags = newFlags andInv PermissionFlags.POLICY_FIXED } } newFlags = if (permission.isHardRestricted && !isExempt) { newFlags or PermissionFlags.RESTRICTION_REVOKED } else { newFlags andInv PermissionFlags.RESTRICTION_REVOKED } newFlags = if (permission.isSoftRestricted && !isExempt) { newFlags or PermissionFlags.SOFT_RESTRICTED } else { newFlags andInv PermissionFlags.SOFT_RESTRICTED } mask = mask or PermissionFlags.RESTRICTION_REVOKED or PermissionFlags.SOFT_RESTRICTED updatePermissionFlags(appId, userId, requestedPermission, mask, newFlags) var exemptFlags = if (requestedPermission in permissionNames) exemptMask else 0 updatePermissionExemptFlags(appId, userId, permission, exemptMask, exemptFlags) } } } Loading
services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt +0 −18 Original line number Diff line number Diff line Loading @@ -233,24 +233,6 @@ class AppIdPermissionPolicyTest : BasePermissionPolicyTest() { .isEqualTo(expectedNewFlags) } @Test fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() { val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.INSTALLER_EXEMPT testOnPackageInstalled( oldFlags, permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED ) {} val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0) val expectedNewFlags = PermissionFlags.INSTALLER_EXEMPT assertWithMessage( "After onPackageInstalled() is called for a non-system app that requests a runtime" + " soft restricted permission that is exempted. The actual permission flags" + " $actualFlags should match the expected flags $expectedNewFlags" ) .that(actualFlags) .isEqualTo(expectedNewFlags) } private fun testOnPackageInstalled( oldFlags: Int, permissionInfoFlags: Int = 0, Loading