diff options
author | Xin Li <delphij@google.com> | 2024-03-06 09:30:09 -0800 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2024-03-06 09:30:09 -0800 |
commit | 3624ef6638b619f2f7bdaea0ce60687582cc6e76 (patch) | |
tree | af45b4b9b8a6479bcd0a0cf50882f598c7892c97 /PermissionController/role-controller/java | |
parent | 92bfe739812beec44c20532857713720d5946294 (diff) | |
parent | 60508898c865eba3829b42017d22bd7f44a64622 (diff) | |
download | Permission-3624ef6638b619f2f7bdaea0ce60687582cc6e76.tar.gz |
Merge Android 14 QPR2 to AOSP main
Bug: 319669529
Merged-In: I9355c44d196061398015858c96f51bc78f8e4374
Change-Id: I26b18315958b277873976b15c2f6d4119c5639bc
Diffstat (limited to 'PermissionController/role-controller/java')
34 files changed, 1580 insertions, 595 deletions
diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java index 12710cfd3..c20734cde 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/AssistantRoleBehavior.java @@ -20,12 +20,12 @@ import android.app.ActivityManager; import android.app.role.RoleManager; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import android.os.Process; import android.os.UserHandle; import android.service.voice.VoiceInteractionService; import android.util.ArraySet; @@ -38,6 +38,7 @@ import androidx.annotation.Nullable; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.model.VisibilityMixin; import com.android.role.controller.util.UserUtils; import org.xmlpull.v1.XmlPullParserException; @@ -54,20 +55,17 @@ public class AssistantRoleBehavior implements RoleBehavior { private static final String LOG_TAG = AssistantRoleBehavior.class.getSimpleName(); - private static final Intent ASSIST_SERVICE_PROBE = - new Intent(VoiceInteractionService.SERVICE_INTERFACE); - private static final Intent ASSIST_ACTIVITY_PROBE = new Intent(Intent.ACTION_ASSIST); - @Override - public void onRoleAdded(@NonNull Role role, @NonNull Context context) { + public void onRoleAddedAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { PackageManager packageManager = context.getPackageManager(); if (packageManager.isDeviceUpgrading()) { RoleManager roleManager = context.getSystemService(RoleManager.class); - List<String> packageNames = roleManager.getRoleHolders(role.getName()); + List<String> packageNames = roleManager.getRoleHoldersAsUser(role.getName(), user); if (packageNames.isEmpty()) { // If the device was upgraded, and there isn't any legacy role holders, it means // user selected "None" in Settings and we need to keep that. - role.onNoneHolderSelectedAsUser(Process.myUserHandle(), context); + role.onNoneHolderSelectedAsUser(user, context); } } } @@ -82,81 +80,72 @@ public class AssistantRoleBehavior implements RoleBehavior { @Override public List<String> getQualifyingPackagesAsUser(@NonNull Role role, @NonNull UserHandle user, @NonNull Context context) { + return getQualifyingPackagesInternal(null, user, context); + } + + @Nullable + @Override + public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + return !getQualifyingPackagesInternal(packageName, user, context) + .isEmpty(); + } + + @NonNull + private List<String> getQualifyingPackagesInternal(@Nullable String filterPackageName, + @NonNull UserHandle user, @NonNull Context context) { Context userContext = UserUtils.getUserContext(context, user); ActivityManager userActivityManager = userContext.getSystemService(ActivityManager.class); PackageManager userPackageManager = userContext.getPackageManager(); - Set<String> availableAssistants = new ArraySet<>(); + Set<String> packageNames = new ArraySet<>(); if (!userActivityManager.isLowRamDevice()) { - List<ResolveInfo> services = userPackageManager.queryIntentServices( - ASSIST_SERVICE_PROBE, PackageManager.GET_META_DATA + Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); + if (filterPackageName != null) { + serviceIntent.setPackage(filterPackageName); + } + List<ResolveInfo> serviceResolveInfos = userPackageManager.queryIntentServices( + serviceIntent, PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); - int numServices = services.size(); - for (int i = 0; i < numServices; i++) { - ResolveInfo service = services.get(i); - - if (isAssistantVoiceInteractionService(userPackageManager, service.serviceInfo)) { - availableAssistants.add(service.serviceInfo.packageName); + int serviceResolveInfosSize = serviceResolveInfos.size(); + for (int i = 0; i < serviceResolveInfosSize; i++) { + ResolveInfo serviceResolveInfo = serviceResolveInfos.get(i); + + ServiceInfo serviceInfo = serviceResolveInfo.serviceInfo; + if (!isAssistantVoiceInteractionService(userPackageManager, serviceInfo)) { + if (filterPackageName != null) { + Log.w(LOG_TAG, "Package " + filterPackageName + + " has an unqualified voice interaction service"); + } + continue; } + + packageNames.add(serviceInfo.packageName); } } - List<ResolveInfo> activities = userPackageManager.queryIntentActivities( - ASSIST_ACTIVITY_PROBE, PackageManager.MATCH_DEFAULT_ONLY + Intent activityIntent = new Intent(Intent.ACTION_ASSIST); + if (filterPackageName != null) { + activityIntent.setPackage(filterPackageName); + } + List<ResolveInfo> activityResolveInfos = userPackageManager.queryIntentActivities( + activityIntent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); - int numActivities = activities.size(); - for (int i = 0; i < numActivities; i++) { - availableAssistants.add(activities.get(i).activityInfo.packageName); - } - - return new ArrayList<>(availableAssistants); - } - - @Nullable - @Override - public Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) { - ActivityManager activityManager = context.getSystemService(ActivityManager.class); - PackageManager packageManager = context.getPackageManager(); - - boolean hasAssistantService = false; - if (!activityManager.isLowRamDevice()) { - Intent pkgServiceProbe = new Intent(ASSIST_SERVICE_PROBE).setPackage(packageName); - List<ResolveInfo> services = packageManager.queryIntentServices(pkgServiceProbe, - PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); - hasAssistantService = !services.isEmpty(); - int numServices = services.size(); - for (int i = 0; i < numServices; i++) { - ResolveInfo service = services.get(i); + int activityResolveInfosSize = activityResolveInfos.size(); + for (int i = 0; i < activityResolveInfosSize; i++) { + ResolveInfo activityResolveInfo = activityResolveInfos.get(i); - if (isAssistantVoiceInteractionService(packageManager, service.serviceInfo)) { - return true; - } + ActivityInfo activityInfo = activityResolveInfo.activityInfo; + if (!activityInfo.exported) { + continue; } - } - Intent pkgActivityProbe = new Intent(ASSIST_ACTIVITY_PROBE).setPackage(packageName); - boolean hasAssistantActivity = !packageManager.queryIntentActivities(pkgActivityProbe, - PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE).isEmpty(); - if (!hasAssistantActivity) { - Log.w(LOG_TAG, "Package " + packageName + " not qualified for " + role.getName() - + " due to " + (hasAssistantService ? "unqualified" : "missing") - + " service and missing activity"); + packageNames.add(activityInfo.packageName); } - return hasAssistantActivity; - } - - @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - } - - @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { + return new ArrayList<>(packageNames); } private boolean isAssistantVoiceInteractionService(@NonNull PackageManager pm, @@ -205,4 +194,10 @@ public class AssistantRoleBehavior implements RoleBehavior { return true; } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return VisibilityMixin.isVisible("config_showDefaultAssistant", false, user, context); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java index 2cf6a0b14..0261e1eee 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/BrowserRoleBehavior.java @@ -21,7 +21,6 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; -import android.os.Process; import android.os.UserHandle; import android.util.ArraySet; @@ -32,6 +31,7 @@ import com.android.modules.utils.build.SdkLevel; import com.android.role.controller.model.Permissions; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.model.VisibilityMixin; import com.android.role.controller.util.CollectionUtils; import com.android.role.controller.util.PackageUtils; import com.android.role.controller.util.UserUtils; @@ -61,10 +61,10 @@ public class BrowserRoleBehavior implements RoleBehavior { @Nullable @Override - public String getFallbackHolder(@NonNull Role role, @NonNull Context context) { - UserHandle user = Process.myUserHandle(); - List<String> qualifyingPackageNames = getQualifyingPackagesAsUserInternal(null, false, user, - context); + public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + List<String> qualifyingPackageNames = getQualifyingPackagesAsUserInternal(null, false, + user, context); if (qualifyingPackageNames.size() == 1) { return qualifyingPackageNames.get(0); } @@ -76,7 +76,7 @@ public class BrowserRoleBehavior implements RoleBehavior { return qualifyingSystemPackageNames.get(0); } - List<String> defaultPackageNames = role.getDefaultHolders(context); + List<String> defaultPackageNames = role.getDefaultHoldersAsUser(user, context); return CollectionUtils.firstOrNull(defaultPackageNames); } else { return null; @@ -95,10 +95,10 @@ public class BrowserRoleBehavior implements RoleBehavior { @Nullable @Override - public Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) { + public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { List<String> packageNames = getQualifyingPackagesAsUserInternal(packageName, false, - Process.myUserHandle(), context); + user, context); return !packageNames.isEmpty(); } @@ -133,24 +133,32 @@ public class BrowserRoleBehavior implements RoleBehavior { } @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { // @see com.android.server.pm.permission.DefaultPermissionGrantPolicy // #grantDefaultPermissionsToDefaultBrowser(java.lang.String, int) if (SdkLevel.isAtLeastS()) { - if (PackageUtils.isSystemPackage(packageName, context)) { - Permissions.grant(packageName, SYSTEM_BROWSER_PERMISSIONS, false, false, true, - false, false, context); + if (PackageUtils.isSystemPackageAsUser(packageName, user, context)) { + Permissions.grantAsUser(packageName, SYSTEM_BROWSER_PERMISSIONS, false, false, + true, false, false, user, context); } } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (SdkLevel.isAtLeastT()) { - if (PackageUtils.isSystemPackage(packageName, context)) { - Permissions.revoke(packageName, SYSTEM_BROWSER_PERMISSIONS, true, false, false, - context); + if (PackageUtils.isSystemPackageAsUser(packageName, user, context)) { + Permissions.revokeAsUser(packageName, SYSTEM_BROWSER_PERMISSIONS, true, false, + false, user, context); } } } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return VisibilityMixin.isVisible("config_showBrowserRole", true, user, context); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java index 131690fd7..c164de3d8 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceAppStreamingRoleBehavior.java @@ -17,12 +17,14 @@ package com.android.role.controller.behavior; import android.content.Context; +import android.os.UserHandle; import androidx.annotation.NonNull; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; import com.android.role.controller.util.NotificationUtils; +import com.android.role.controller.util.UserUtils; /** * Class for behavior of the "App Streaming" Companion device profile role. @@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils; public class CompanionDeviceAppStreamingRoleBehavior implements RoleBehavior { @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.grantNotificationAccessForPackage(context, packageName); + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context); + } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.revokeNotificationAccessForPackage(context, packageName); + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context); + } } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java index c59d5e58d..e5d996675 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceComputerRoleBehavior.java @@ -17,12 +17,14 @@ package com.android.role.controller.behavior; import android.content.Context; +import android.os.UserHandle; import androidx.annotation.NonNull; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; import com.android.role.controller.util.NotificationUtils; +import com.android.role.controller.util.UserUtils; /** * Class for behavior of the "Computer" Companion device profile role. @@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils; public class CompanionDeviceComputerRoleBehavior implements RoleBehavior { @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.grantNotificationAccessForPackage(context, packageName); + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context); + } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.revokeNotificationAccessForPackage(context, packageName); + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context); + } } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java index 2e4691b9c..5464a1518 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceGlassesRoleBehavior.java @@ -17,12 +17,14 @@ package com.android.role.controller.behavior; import android.content.Context; +import android.os.UserHandle; import androidx.annotation.NonNull; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; import com.android.role.controller.util.NotificationUtils; +import com.android.role.controller.util.UserUtils; /** * Class for behavior of the "glasses" Companion device profile role. @@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils; public class CompanionDeviceGlassesRoleBehavior implements RoleBehavior { @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.grantNotificationAccessForPackage(context, packageName); + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context); + } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.revokeNotificationAccessForPackage(context, packageName); + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context); + } } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java index 233c0d92e..0645c84d1 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/CompanionDeviceWatchRoleBehavior.java @@ -17,12 +17,14 @@ package com.android.role.controller.behavior; import android.content.Context; +import android.os.UserHandle; import androidx.annotation.NonNull; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; import com.android.role.controller.util.NotificationUtils; +import com.android.role.controller.util.UserUtils; /** * Class for behavior of the "watch" Companion device profile role. @@ -30,12 +32,18 @@ import com.android.role.controller.util.NotificationUtils; public class CompanionDeviceWatchRoleBehavior implements RoleBehavior { @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.grantNotificationAccessForPackage(context, packageName); + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.grantNotificationAccessForPackageAsUser(packageName, user, context); + } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - NotificationUtils.revokeNotificationAccessForPackage(context, packageName); + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (!UserUtils.isManagedProfile(user, context)) { + NotificationUtils.revokeNotificationAccessForPackageAsUser(packageName, user, context); + } } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java index 79c139cee..57b5412dc 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DialerRoleBehavior.java @@ -26,6 +26,7 @@ import com.android.modules.utils.build.SdkLevel; import com.android.role.controller.model.Permissions; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.model.VisibilityMixin; import com.android.role.controller.util.PackageUtils; import java.util.Arrays; @@ -55,20 +56,28 @@ public class DialerRoleBehavior implements RoleBehavior { } @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (SdkLevel.isAtLeastS()) { - if (PackageUtils.isSystemPackage(packageName, context)) { - Permissions.grant(packageName, SYSTEM_DIALER_PERMISSIONS, false, false, - true, false, false, context); + if (PackageUtils.isSystemPackageAsUser(packageName, user, context)) { + Permissions.grantAsUser(packageName, SYSTEM_DIALER_PERMISSIONS, false, false, + true, false, false, user, context); } } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) { + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (SdkLevel.isAtLeastS()) { - Permissions.revoke(packageName, SYSTEM_DIALER_PERMISSIONS, true, false, false, context); + Permissions.revokeAsUser(packageName, SYSTEM_DIALER_PERMISSIONS, true, false, false, + user, context); } } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return VisibilityMixin.isVisible("config_showDialerRole", true, user, context); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java index ee7984274..fa030a00a 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/DocumentManagerRoleBehavior.java @@ -17,7 +17,7 @@ package com.android.role.controller.behavior; import android.content.Context; -import android.os.Process; +import android.os.UserHandle; import android.util.Log; import androidx.annotation.NonNull; @@ -36,9 +36,9 @@ public class DocumentManagerRoleBehavior implements RoleBehavior { @NonNull @Override - public List<String> getDefaultHolders(@NonNull Role role, @NonNull Context context) { - List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser( - Process.myUserHandle(), context); + public List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(user, context); if (qualifyingPackageNames.size() == 1) { return qualifyingPackageNames; } else { diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java index a54006bb5..f19c86596 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/EmergencyRoleBehavior.java @@ -18,7 +18,6 @@ package com.android.role.controller.behavior; import android.content.Context; import android.content.pm.PackageInfo; -import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; @@ -27,6 +26,7 @@ import androidx.annotation.Nullable; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.model.VisibilityMixin; import com.android.role.controller.util.PackageUtils; import java.util.List; @@ -49,15 +49,16 @@ public class EmergencyRoleBehavior implements RoleBehavior { @Nullable @Override - public String getFallbackHolder(@NonNull Role role, @NonNull Context context) { - List<String> packageNames = role.getQualifyingPackagesAsUser(Process.myUserHandle(), - context); + public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + List<String> packageNames = role.getQualifyingPackagesAsUser(user, context); PackageInfo fallbackPackageInfo = null; int packageNamesSize = packageNames.size(); for (int i = 0; i < packageNamesSize; i++) { String packageName = packageNames.get(i); - PackageInfo packageInfo = PackageUtils.getPackageInfo(packageName, 0, context); + PackageInfo packageInfo = PackageUtils.getPackageInfoAsUser(packageName, 0, + user, context); if (packageInfo == null) { continue; } @@ -68,4 +69,10 @@ public class EmergencyRoleBehavior implements RoleBehavior { } return fallbackPackageInfo != null ? fallbackPackageInfo.packageName : null; } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return VisibilityMixin.isVisible("config_showDefaultEmergency", false, user, context); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java index 3254bc6e4..4bf5a6294 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/HomeRoleBehavior.java @@ -22,15 +22,20 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.content.pm.ResolveInfo; +import android.os.Build; import android.os.UserHandle; import android.provider.Settings; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import com.android.modules.utils.build.SdkLevel; +import com.android.role.controller.model.AppOpPermissions; import com.android.role.controller.model.Permissions; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.model.VisibilityMixin; import com.android.role.controller.util.UserUtils; import java.util.Arrays; @@ -51,6 +56,18 @@ public class HomeRoleBehavior implements RoleBehavior { android.Manifest.permission.WRITE_CALL_LOG, android.Manifest.permission.READ_CONTACTS); + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + private static final List<String> WEAR_PERMISSIONS_T = Arrays.asList( + android.Manifest.permission.POST_NOTIFICATIONS, + android.Manifest.permission.SYSTEM_APPLICATION_OVERLAY); + + @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static final List<String> WEAR_PERMISSIONS_V = Arrays.asList( + android.Manifest.permission.ALWAYS_UPDATE_WALLPAPER); + + private static final List<String> WEAR_APP_OP_PERMISSIONS = Arrays.asList( + android.Manifest.permission.SYSTEM_ALERT_WINDOW); + @Override public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user, @NonNull Context context) { @@ -62,10 +79,12 @@ public class HomeRoleBehavior implements RoleBehavior { */ @Nullable @Override - public String getFallbackHolder(@NonNull Role role, @NonNull Context context) { - PackageManager packageManager = context.getPackageManager(); + public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); Intent intent = role.getRequiredComponents().get(0).getIntentFilterData().createIntent(); - List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, + List<ResolveInfo> resolveInfos = userPackageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); @@ -78,7 +97,8 @@ public class HomeRoleBehavior implements RoleBehavior { // Leave the fallback to PackageManagerService if there is only the fallback home in // Settings, because if we fallback to it here, we cannot fallback to a normal home // later, and user cannot see the fallback home in the UI anyway. - if (isSettingsApplication(resolveInfo.activityInfo.applicationInfo, context)) { + if (isSettingsApplicationAsUser(resolveInfo.activityInfo.applicationInfo, user, + context)) { continue; } if (resolveInfo.priority > priority) { @@ -94,14 +114,16 @@ public class HomeRoleBehavior implements RoleBehavior { /** * Check if the application is a settings application */ - public static boolean isSettingsApplication(@NonNull ApplicationInfo applicationInfo, - @NonNull Context context) { - PackageManager packageManager = context.getPackageManager(); - ResolveInfo resolveInfo = packageManager.resolveActivity(new Intent( - Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY + private static boolean isSettingsApplicationAsUser(@NonNull ApplicationInfo applicationInfo, + @NonNull UserHandle user, @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); + ResolveInfo resolveInfo = userPackageManager.resolveActivity( + new Intent(Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); - if (resolveInfo == null || resolveInfo.activityInfo == null) { + if (resolveInfo == null || resolveInfo.activityInfo == null + || !resolveInfo.activityInfo.exported) { return false; } return Objects.equals(applicationInfo.packageName, resolveInfo.activityInfo.packageName); @@ -119,31 +141,62 @@ public class HomeRoleBehavior implements RoleBehavior { } @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { - Permissions.grant(packageName, AUTOMOTIVE_PERMISSIONS, - true, false, true, false, false, context); + Permissions.grantAsUser(packageName, AUTOMOTIVE_PERMISSIONS, + true, false, true, false, false, user, context); } // Before T, ALLOW_SLIPPERY_TOUCHES may either not exist, or may not be a role permission if (isRolePermission(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES, context)) { - Permissions.grant(packageName, + Permissions.grantAsUser(packageName, Arrays.asList(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES), - true, false, true, false, false, context); + true, false, true, false, false, user, context); + } + + if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { + if (SdkLevel.isAtLeastT()) { + Permissions.grantAsUser(packageName, WEAR_PERMISSIONS_T, + true, false, true, false, false, user, context); + for (String permission : WEAR_APP_OP_PERMISSIONS) { + AppOpPermissions.grantAsUser(packageName, permission, true, user, context); + } + } + if (SdkLevel.isAtLeastV()) { + Permissions.grantAsUser(packageName, WEAR_PERMISSIONS_V, + true, false, true, false, false, user, context); + } } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { - Permissions.revoke(packageName, AUTOMOTIVE_PERMISSIONS, true, false, false, context); + Permissions.revokeAsUser(packageName, AUTOMOTIVE_PERMISSIONS, true, false, false, + user, context); } // Before T, ALLOW_SLIPPERY_TOUCHES may either not exist, or may not be a role permission if (isRolePermission(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES, context)) { - Permissions.revoke(packageName, + Permissions.revokeAsUser(packageName, Arrays.asList(android.Manifest.permission.ALLOW_SLIPPERY_TOUCHES), - true, false, false, context); + true, false, false, user, context); + } + + if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { + if (SdkLevel.isAtLeastT()) { + Permissions.revokeAsUser(packageName, WEAR_PERMISSIONS_T, true, false, false, + user, context); + for (String permission : WEAR_APP_OP_PERMISSIONS) { + AppOpPermissions.revokeAsUser(packageName, permission, user, context); + } + } + if (SdkLevel.isAtLeastV()) { + Permissions.revokeAsUser(packageName, WEAR_PERMISSIONS_V, true, false, false, + user, context); + } } } @@ -161,4 +214,17 @@ public class HomeRoleBehavior implements RoleBehavior { final int flags = permissionInfo.getProtectionFlags(); return (flags & PermissionInfo.PROTECTION_FLAG_ROLE) == PermissionInfo.PROTECTION_FLAG_ROLE; } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return VisibilityMixin.isVisible("config_showDefaultHome", false, user, context); + } + + @Override + public boolean isApplicationVisibleAsUser(@NonNull Role role, + @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user, + @NonNull Context context) { + return !isSettingsApplicationAsUser(applicationInfo, user, context); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java new file mode 100644 index 000000000..6dcdafd4c --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/RetailDemoRoleBehavior.java @@ -0,0 +1,65 @@ +/* + * 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.role.controller.behavior; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import com.android.role.controller.model.Role; +import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.util.UserUtils; + +/** + * Class for behavior of the Retail Demo role. + */ +@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) +public class RetailDemoRoleBehavior implements RoleBehavior { + + @Override + public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (Settings.Global.getInt(context.getContentResolver(), + Settings.Global.DEVICE_DEMO_MODE, 0) == 0) { + return false; + } + Context userContext = UserUtils.getUserContext(context, user); + DevicePolicyManager userDevicePolicyManager = + userContext.getSystemService(DevicePolicyManager.class); + if (!(userDevicePolicyManager.isDeviceOwnerApp(packageName) + || userDevicePolicyManager.isProfileOwnerApp(packageName))) { + return false; + } + // Fallback to do additional default check. + return null; + } + + @Override + public boolean isAvailableAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + UserManager userUserManager = userContext.getSystemService(UserManager.class); + return userUserManager.isSystemUser() || userUserManager.isMainUser() + || userUserManager.isDemoUser(); + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java index c1186a930..b614594c5 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SmsRoleBehavior.java @@ -19,7 +19,6 @@ package com.android.role.controller.behavior; import android.app.admin.DevicePolicyManager; import android.app.admin.ManagedSubscriptionsPolicy; import android.content.Context; -import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.telephony.TelephonyManager; @@ -31,6 +30,7 @@ import com.android.modules.utils.build.SdkLevel; import com.android.role.controller.model.Permissions; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.model.VisibilityMixin; import com.android.role.controller.util.CollectionUtils; import com.android.role.controller.util.PackageUtils; import com.android.role.controller.util.UserUtils; @@ -90,7 +90,7 @@ public class SmsRoleBehavior implements RoleBehavior { TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); if (!telephonyManager.isSmsCapable() // Ensure sms role is present on car despite !isSmsCapable config (b/132972702) - && role.getDefaultHolders(context).isEmpty()) { + && role.getDefaultHoldersAsUser(user, context).isEmpty()) { return false; } return true; @@ -98,8 +98,9 @@ public class SmsRoleBehavior implements RoleBehavior { @Nullable @Override - public String getFallbackHolder(@NonNull Role role, @NonNull Context context) { - List<String> defaultPackageNames = role.getDefaultHolders(context); + public String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + List<String> defaultPackageNames = role.getDefaultHoldersAsUser(user, context); if (!defaultPackageNames.isEmpty()) { return defaultPackageNames.get(0); } @@ -107,24 +108,32 @@ public class SmsRoleBehavior implements RoleBehavior { // TODO(b/132916161): This was the previous behavior, however this may allow any third-party // app to suddenly become the default SMS app and get the permissions, if no system default // SMS app is available. - List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser( - Process.myUserHandle(), context); + List<String> qualifyingPackageNames = role.getQualifyingPackagesAsUser(user, context); return CollectionUtils.firstOrNull(qualifyingPackageNames); } @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - if (SdkLevel.isAtLeastS() && PackageUtils.isSystemPackage(packageName, context)) { - Permissions.grant(packageName, SYSTEM_SMS_PERMISSIONS, false, false, - true, false, false, context); + public void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + if (SdkLevel.isAtLeastS() && PackageUtils.isSystemPackageAsUser(packageName, user, + context)) { + Permissions.grantAsUser(packageName, SYSTEM_SMS_PERMISSIONS, false, false, true, + false, false, user, context); } } @Override - public void revoke(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) { + public void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (SdkLevel.isAtLeastS()) { - Permissions.revoke(packageName, SYSTEM_SMS_PERMISSIONS, true, false, false, context); + Permissions.revokeAsUser(packageName, SYSTEM_SMS_PERMISSIONS, true, false, false, + user, context); } } + + @Override + public boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return VisibilityMixin.isVisible("config_showSmsRole", true, user, context); + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java index c0cbe9c25..621955770 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemShellRoleBehavior.java @@ -26,6 +26,7 @@ import androidx.annotation.Nullable; import com.android.role.controller.model.Role; import com.android.role.controller.model.RoleBehavior; +import com.android.role.controller.util.UserUtils; /** * Class for behavior of the system shell role. @@ -33,12 +34,13 @@ import com.android.role.controller.model.RoleBehavior; public class SystemShellRoleBehavior implements RoleBehavior { @Nullable @Override - public Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) { - PackageManager packageManager = context.getPackageManager(); + public Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); int uid; try { - uid = packageManager.getPackageUid(packageName, 0); + uid = userPackageManager.getPackageUid(packageName, 0); } catch (PackageManager.NameNotFoundException e) { return false; } diff --git a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java deleted file mode 100644 index 210c2313f..000000000 --- a/PermissionController/role-controller/java/com/android/role/controller/behavior/SystemUiRoleBehavior.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2021 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.role.controller.behavior; - -import android.content.Context; -import android.content.pm.PackageManager; - -import androidx.annotation.NonNull; - -import com.android.modules.utils.build.SdkLevel; -import com.android.role.controller.model.AppOpPermissions; -import com.android.role.controller.model.Role; -import com.android.role.controller.model.RoleBehavior; - -import java.util.Arrays; -import java.util.List; - -/** The role behavior for system ui. */ -public class SystemUiRoleBehavior implements RoleBehavior { - - private static final List<String> WEAR_APP_OP_PERMISSIONS = - Arrays.asList(android.Manifest.permission.SYSTEM_ALERT_WINDOW); - - @Override - public void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - if (SdkLevel.isAtLeastT()) { - if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { - for (String permission : WEAR_APP_OP_PERMISSIONS) { - AppOpPermissions.grant(packageName, permission, true, context); - } - } - } - } - - @Override - public void revoke(@NonNull Role role, @NonNull String packageName, @NonNull Context context) { - if (SdkLevel.isAtLeastT()) { - if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) { - for (String permission : WEAR_APP_OP_PERMISSIONS) { - AppOpPermissions.revoke(packageName, permission, context); - } - } - } - } -} diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java index 3efa68bc9..6647a4f94 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOp.java @@ -18,7 +18,7 @@ package com.android.role.controller.model; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.os.Process; +import android.os.UserHandle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -73,39 +73,44 @@ public class AppOp { * Grant this app op to an application. * * @param packageName the package name of the application + * @param user the user of the application * @param context the {@code Context} to retrieve system services * * @return whether any app mode has changed */ - public boolean grant(@NonNull String packageName, @NonNull Context context) { - if (!checkTargetSdkVersion(packageName, context)) { + public boolean grantAsUser(@NonNull String packageName, @NonNull UserHandle user, + @NonNull Context context) { + if (!checkTargetSdkVersionAsUser(packageName, user, context)) { return false; } - return Permissions.setAppOpUidMode(packageName, mName, mMode, context); + return Permissions.setAppOpUidModeAsUser(packageName, mName, mMode, user, context); } /** * Revoke this app op from an application. * * @param packageName the package name of the application + * @param user the user of the application * @param context the {@code Context} to retrieve system services * * @return whether any app mode has changed */ - public boolean revoke(@NonNull String packageName, @NonNull Context context) { - if (!checkTargetSdkVersion(packageName, context)) { + public boolean revokeAsUser(@NonNull String packageName, @NonNull UserHandle user, + @NonNull Context context) { + if (!checkTargetSdkVersionAsUser(packageName, user, context)) { return false; } int defaultMode = Permissions.getDefaultAppOpMode(mName); - return Permissions.setAppOpUidMode(packageName, mName, defaultMode, context); + return Permissions.setAppOpUidModeAsUser(packageName, mName, defaultMode, user, context); } - private boolean checkTargetSdkVersion(@NonNull String packageName, @NonNull Context context) { + private boolean checkTargetSdkVersionAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { if (mMaxTargetSdkVersion == null) { return true; } - ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, + context); if (applicationInfo == null) { return false; } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java index 29939a1a5..edd74e31e 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/AppOpPermissions.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; +import android.os.UserHandle; import androidx.annotation.NonNull; @@ -42,14 +43,15 @@ public class AppOpPermissions { * @param appOpPermission the name of the app op permission * @param overrideNonDefaultMode whether to override the app opp mode if it isn't in the default * mode + * @param user the user of the application * @param context the {@code Context} to retrieve system services * * @return whether any app op mode has changed */ - public static boolean grant(@NonNull String packageName, @NonNull String appOpPermission, - boolean overrideNonDefaultMode, @NonNull Context context) { - PackageInfo packageInfo = PackageUtils.getPackageInfo(packageName, - PackageManager.GET_PERMISSIONS, context); + public static boolean grantAsUser(@NonNull String packageName, @NonNull String appOpPermission, + boolean overrideNonDefaultMode, @NonNull UserHandle user, @NonNull Context context) { + PackageInfo packageInfo = PackageUtils.getPackageInfoAsUser(packageName, + PackageManager.GET_PERMISSIONS, user, context); if (packageInfo == null) { return false; } @@ -58,14 +60,16 @@ public class AppOpPermissions { } String appOp = AppOpsManagerCompat.permissionToOp(appOpPermission); if (!overrideNonDefaultMode) { - Integer currentMode = Permissions.getAppOpMode(packageName, appOp, context); + Integer currentMode = Permissions.getAppOpModeAsUser(packageName, appOp, user, context); if (currentMode != null && currentMode != Permissions.getDefaultAppOpMode(appOp)) { return false; } } - boolean changed = setAppOpMode(packageName, appOp, AppOpsManager.MODE_ALLOWED, context); + boolean changed = setAppOpModeAsUser(packageName, appOp, AppOpsManager.MODE_ALLOWED, user, + context); if (changed) { - Permissions.setPermissionGrantedByRole(packageName, appOpPermission, true, context); + Permissions.setPermissionGrantedByRoleAsUser(packageName, appOpPermission, true, + user, context); } return changed; } @@ -75,24 +79,27 @@ public class AppOpPermissions { * * @param packageName the package name of the application * @param appOpPermission the name of the app op permission + * @param user the user of the application * @param context the {@code Context} to retrieve system services * * @return whether any app op mode has changed */ - public static boolean revoke(@NonNull String packageName, @NonNull String appOpPermission, - @NonNull Context context) { - if (!Permissions.isPermissionGrantedByRole(packageName, appOpPermission, context)) { + public static boolean revokeAsUser(@NonNull String packageName, @NonNull String appOpPermission, + @NonNull UserHandle user, @NonNull Context context) { + if (!Permissions.isPermissionGrantedByRoleAsUser(packageName, appOpPermission, user, + context)) { return false; } String appOp = AppOpsManager.permissionToOp(appOpPermission); int defaultMode = Permissions.getDefaultAppOpMode(appOp); - boolean changed = setAppOpMode(packageName, appOp, defaultMode, context); - Permissions.setPermissionGrantedByRole(packageName, appOpPermission, false, context); + boolean changed = setAppOpModeAsUser(packageName, appOp, defaultMode, user, context); + Permissions.setPermissionGrantedByRoleAsUser(packageName, appOpPermission, false, + user, context); return changed; } - private static boolean setAppOpMode(@NonNull String packageName, @NonNull String appOp, - int mode, @NonNull Context context) { + private static boolean setAppOpModeAsUser(@NonNull String packageName, @NonNull String appOp, + int mode, @NonNull UserHandle user, @NonNull Context context) { switch (appOp) { case AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS: case AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW: @@ -105,22 +112,25 @@ public class AppOpPermissions { case AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS: case AppOpsManager.OPSTR_INSTANT_APP_START_FOREGROUND: case AppOpsManager.OPSTR_LOADER_USAGE_STATS: - return Permissions.setAppOpPackageMode(packageName, appOp, mode, context); + return Permissions.setAppOpPackageModeAsUser(packageName, appOp, mode, user, + context); case AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // We fixed OP_INTERACT_ACROSS_PROFILES to use UID mode on S and backported it // to R, but still, we might have an out-of-date platform or an upgraded // platform with old state. boolean changed = false; - changed |= Permissions.setAppOpUidMode(packageName, appOp, mode, context); - changed |= Permissions.setAppOpPackageMode(packageName, appOp, - Permissions.getDefaultAppOpMode(appOp), context); + changed |= Permissions.setAppOpUidModeAsUser(packageName, appOp, mode, user, + context); + changed |= Permissions.setAppOpPackageModeAsUser(packageName, appOp, + Permissions.getDefaultAppOpMode(appOp), user, context); return changed; } else { - return Permissions.setAppOpPackageMode(packageName, appOp, mode, context); + return Permissions.setAppOpPackageModeAsUser(packageName, appOp, mode, user, + context); } default: - return Permissions.setAppOpUidMode(packageName, appOp, mode, context); + return Permissions.setAppOpUidModeAsUser(packageName, appOp, mode, user, context); } } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java index 0c4a14574..6ded32d58 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permission.java @@ -60,14 +60,29 @@ public class Permission { * @return whether this permission is available */ public boolean isAvailable() { - // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization. - if (mMinSdkVersion >= 34) { - return SdkLevel.isAtLeastU(); + // Workaround to match the value 35+ for V+ in roles.xml before SDK finalization. + if (mMinSdkVersion >= 35) { + return SdkLevel.isAtLeastV(); } else { return Build.VERSION.SDK_INT >= mMinSdkVersion; } } + /** + * Return a new permission with the specified minimum SDK version, or this permission if it + * already has the same minimum SDK version. + * + * @param minSdkVersion the minimum SDK version + * @return a permission with the specified minimum SDK version + */ + @NonNull + public Permission withMinSdkVersion(int minSdkVersion) { + if (mMinSdkVersion == minSdkVersion) { + return this; + } + return new Permission(mName, minSdkVersion); + } + @Override public String toString() { return "Permission{" diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java index f55a84c07..8a15612b9 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Permissions.java @@ -24,7 +24,6 @@ import android.content.pm.PackageManager; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.os.Build; -import android.os.Process; import android.os.UserHandle; import android.permission.PermissionManager; import android.util.ArrayMap; @@ -37,6 +36,7 @@ import androidx.annotation.Nullable; import com.android.role.controller.util.ArrayUtils; import com.android.role.controller.util.CollectionUtils; import com.android.role.controller.util.PackageUtils; +import com.android.role.controller.util.UserUtils; import java.util.ArrayList; import java.util.List; @@ -89,6 +89,7 @@ public class Permissions { * @param setGrantedByRole whether the permissions will be granted as granted-by-role * @param setGrantedByDefault whether the permissions will be granted as granted-by-default * @param setSystemFixed whether the permissions will be granted as system-fixed + * @param user the user of the application * @param context the {@code Context} to retrieve system services * * @return whether any permission or app op changed @@ -96,16 +97,16 @@ public class Permissions { * @see com.android.server.pm.permission.DefaultPermissionGrantPolicy#grantRuntimePermissions( * PackageInfo, java.util.Set, boolean, boolean, int) */ - public static boolean grant(@NonNull String packageName, @NonNull List<String> permissions, - boolean overrideDisabledSystemPackage, boolean overrideUserSetAndFixed, - boolean setGrantedByRole, boolean setGrantedByDefault, boolean setSystemFixed, - @NonNull Context context) { + public static boolean grantAsUser(@NonNull String packageName, + @NonNull List<String> permissions, boolean overrideDisabledSystemPackage, + boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault, + boolean setSystemFixed, @NonNull UserHandle user, @NonNull Context context) { if (setGrantedByRole == setGrantedByDefault) { throw new IllegalArgumentException("Permission must be either granted by role, or" + " granted by default, but not both"); } - PackageInfo packageInfo = getPackageInfo(packageName, context); + PackageInfo packageInfo = getPackageInfoAsUser(packageName, user, context); if (packageInfo == null) { return false; } @@ -142,7 +143,8 @@ public class Permissions { // apps, (default grants on first boot and user creation) we don't grant default // permissions if the version on the system image does not declare them. if (!overrideDisabledSystemPackage && isUpdatedSystemApp(packageInfo)) { - PackageInfo disabledSystemPackageInfo = getFactoryPackageInfo(packageName, context); + PackageInfo disabledSystemPackageInfo = getFactoryPackageInfoAsUser(packageName, user, + context); if (disabledSystemPackageInfo != null) { if (ArrayUtils.isEmpty(disabledSystemPackageInfo.requestedPermissions)) { return false; @@ -176,9 +178,10 @@ public class Permissions { boolean permissionOrAppOpChanged = false; - PackageManager packageManager = context.getPackageManager(); + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); Set<String> whitelistedRestrictedPermissions = new ArraySet<>( - packageManager.getWhitelistedRestrictedPermissions(packageName, + userPackageManager.getWhitelistedRestrictedPermissions(packageName, PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)); int sortedPermissionsToGrantLength = sortedPermissionsToGrant.length; @@ -187,24 +190,26 @@ public class Permissions { if (isRestrictedPermission(permission, context) && whitelistedRestrictedPermissions.add(permission)) { - packageManager.addWhitelistedRestrictedPermission(packageName, permission, + userPackageManager.addWhitelistedRestrictedPermission(packageName, permission, PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM); } - permissionOrAppOpChanged |= grantSingle(packageName, permission, + permissionOrAppOpChanged |= grantSingleAsUser(packageName, permission, overrideUserSetAndFixed, setGrantedByRole, setGrantedByDefault, setSystemFixed, - context); + user, context); } return permissionOrAppOpChanged; } - private static boolean grantSingle(@NonNull String packageName, @NonNull String permission, - boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault, - boolean setSystemFixed, @NonNull Context context) { - boolean wasPermissionOrAppOpGranted = isPermissionAndAppOpGranted(packageName, permission, - context); - if (isPermissionFixed(packageName, permission, false, overrideUserSetAndFixed, context) + private static boolean grantSingleAsUser(@NonNull String packageName, + @NonNull String permission, boolean overrideUserSetAndFixed, boolean setGrantedByRole, + boolean setGrantedByDefault, boolean setSystemFixed, @NonNull UserHandle user, + @NonNull Context context) { + boolean wasPermissionOrAppOpGranted = isPermissionAndAppOpGrantedAsUser(packageName, + permission, user, context); + if (isPermissionFixedAsUser(packageName, permission, false, + overrideUserSetAndFixed, user, context) && !wasPermissionOrAppOpGranted) { // Stop granting if this permission is fixed to revoked. return false; @@ -217,7 +222,8 @@ public class Permissions { for (int i = 0; i < foregroundPermissionsSize; i++) { String foregroundPermission = foregroundPermissions.get(i); - if (isPermissionAndAppOpGranted(packageName, foregroundPermission, context)) { + if (isPermissionAndAppOpGrantedAsUser(packageName, foregroundPermission, user, + context)) { isAnyForegroundPermissionGranted = true; break; } @@ -230,8 +236,8 @@ public class Permissions { } } - boolean permissionOrAppOpChanged = grantPermissionAndAppOp(packageName, permission, - context); + boolean permissionOrAppOpChanged = grantPermissionAndAppOpAsUser(packageName, permission, + user, context); // Update permission flags. int newFlags = 0; @@ -254,7 +260,7 @@ public class Permissions { // If a component gets a permission for being the default handler A and also default handler // B, we grant the weaker grant form. This only applies to default permission grant. if (setGrantedByDefault && !setSystemFixed) { - int oldFlags = getPermissionFlags(packageName, permission, context); + int oldFlags = getPermissionFlagsAsUser(packageName, permission, user, context); if ((oldFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0 && (oldFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { if (DEBUG) { @@ -265,20 +271,22 @@ public class Permissions { } } - setPermissionFlags(packageName, permission, newFlags, newMask, context); + setPermissionFlagsAsUser(packageName, permission, newFlags, newMask, + user, context); return permissionOrAppOpChanged; } - private static boolean isPermissionAndAppOpGranted(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { + private static boolean isPermissionAndAppOpGrantedAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { // Check this permission. - if (!isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) { + if (!isPermissionGrantedWithoutCheckingAppOpAsUser(packageName, permission, user, + context)) { return false; } // Check if the permission is review required. - if (isPermissionReviewRequired(packageName, permission, context)) { + if (isPermissionReviewRequiredAsUser(packageName, permission, user, context)) { return false; } @@ -288,7 +296,7 @@ public class Permissions { if (appOp == null) { return true; } - Integer appOpMode = getAppOpMode(packageName, appOp, context); + Integer appOpMode = getAppOpModeAsUser(packageName, appOp, user, context); if (appOpMode == null) { return false; } @@ -314,7 +322,8 @@ public class Permissions { if (foregroundAppOp == null) { continue; } - Integer foregroundAppOpMode = getAppOpMode(packageName, foregroundAppOp, context); + Integer foregroundAppOpMode = getAppOpModeAsUser(packageName, foregroundAppOp, + user, context); if (foregroundAppOpMode == null) { continue; } @@ -326,11 +335,11 @@ public class Permissions { } } - private static boolean grantPermissionAndAppOp(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { + private static boolean grantPermissionAndAppOpAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { // Grant the permission. - boolean permissionOrAppOpChanged = grantPermissionWithoutAppOp(packageName, permission, - context); + boolean permissionOrAppOpChanged = grantPermissionWithoutAppOpAsUser(packageName, + permission, user, context); // Grant the app op. if (!isBackgroundPermission(permission, context)) { @@ -345,13 +354,15 @@ public class Permissions { // This permission is a foreground permission, set its app op mode according to // whether its background permission is granted. String backgroundPermission = getBackgroundPermission(permission, context); - if (!isPermissionAndAppOpGranted(packageName, backgroundPermission, context)) { + if (!isPermissionAndAppOpGrantedAsUser(packageName, backgroundPermission, + user, context)) { appOpMode = AppOpsManager.MODE_FOREGROUND; } else { appOpMode = AppOpsManager.MODE_ALLOWED; } } - permissionOrAppOpChanged |= setAppOpUidMode(packageName, appOp, appOpMode, context); + permissionOrAppOpChanged |= setAppOpUidModeAsUser(packageName, appOp, appOpMode, + user, context); } } else { // This permission is a background permission, set all its foreground permissions' app @@ -365,8 +376,8 @@ public class Permissions { if (foregroundAppOp == null) { continue; } - permissionOrAppOpChanged |= setAppOpUidMode(packageName, foregroundAppOp, - AppOpsManager.MODE_ALLOWED, context); + permissionOrAppOpChanged |= setAppOpUidModeAsUser(packageName, foregroundAppOp, + AppOpsManager.MODE_ALLOWED, user, context); } } @@ -382,16 +393,18 @@ public class Permissions { * @param onlyIfGrantedByDefault revoke the permission only if it is granted by default * @param overrideSystemFixed whether system-fixed permissions can be revoked * @param context the {@code Context} to retrieve system services + * @param user the user of the application * * @return whether any permission or app op changed * * @see com.android.server.pm.permission.DefaultPermissionGrantPolicy#revokeRuntimePermissions( * String, java.util.Set, boolean, int) */ - public static boolean revoke(@NonNull String packageName, @NonNull List<String> permissions, - boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault, - boolean overrideSystemFixed, @NonNull Context context) { - PackageInfo packageInfo = getPackageInfo(packageName, context); + public static boolean revokeAsUser(@NonNull String packageName, + @NonNull List<String> permissions, boolean onlyIfGrantedByRole, + boolean onlyIfGrantedByDefault, boolean overrideSystemFixed, @NonNull UserHandle user, + @NonNull Context context) { + PackageInfo packageInfo = getPackageInfoAsUser(packageName, user, context); if (packageInfo == null) { return false; } @@ -425,9 +438,10 @@ public class Permissions { } } - PackageManager packageManager = context.getPackageManager(); + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); Set<String> whitelistedRestrictedPermissions = - packageManager.getWhitelistedRestrictedPermissions(packageName, + userPackageManager.getWhitelistedRestrictedPermissions(packageName, PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER); @@ -438,13 +452,14 @@ public class Permissions { for (int i = 0; i < sortedPermissionsToRevokeLength; i++) { String permission = sortedPermissionsToRevoke[i]; - permissionOrAppOpChanged |= revokeSingle(packageName, permission, onlyIfGrantedByRole, - onlyIfGrantedByDefault, overrideSystemFixed, context); + permissionOrAppOpChanged |= revokeSingleAsUser(packageName, permission, + onlyIfGrantedByRole, onlyIfGrantedByDefault, overrideSystemFixed, user, + context); // Remove from the system whitelist only if not granted by default. - if (!isPermissionGrantedByDefault(packageName, permission, context) + if (!isPermissionGrantedByDefaultAsUser(packageName, permission, user, context) && whitelistedRestrictedPermissions.remove(permission)) { - packageManager.removeWhitelistedRestrictedPermission(packageName, permission, + userPackageManager.removeWhitelistedRestrictedPermission(packageName, permission, PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM); } } @@ -452,59 +467,62 @@ public class Permissions { return permissionOrAppOpChanged; } - private static boolean revokeSingle(@NonNull String packageName, @NonNull String permission, - boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault, - boolean overrideSystemFixed, @NonNull Context context) { + private static boolean revokeSingleAsUser(@NonNull String packageName, + @NonNull String permission, boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault, + boolean overrideSystemFixed, @NonNull UserHandle user, @NonNull Context context) { if (onlyIfGrantedByRole == onlyIfGrantedByDefault) { throw new IllegalArgumentException("Permission can be revoked only if either granted by" + " role, or granted by default, but not both"); } if (onlyIfGrantedByRole) { - if (!isPermissionGrantedByRole(packageName, permission, context)) { + if (!isPermissionGrantedByRoleAsUser(packageName, permission, user, context)) { return false; } - setPermissionFlags(packageName, permission, 0, - PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, context); + setPermissionFlagsAsUser(packageName, permission, 0, + PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, user, context); } if (onlyIfGrantedByDefault) { - if (!isPermissionGrantedByDefault(packageName, permission, context)) { + if (!isPermissionGrantedByDefaultAsUser(packageName, permission, user, context)) { return false; } // Remove the granted-by-default permission flag. - setPermissionFlags(packageName, permission, 0, - PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, context); + setPermissionFlagsAsUser(packageName, permission, 0, + PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, user, context); // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains sticky once // set. } - if (isPermissionFixed(packageName, permission, overrideSystemFixed, false, context) - && isPermissionAndAppOpGranted(packageName, permission, context)) { + if (isPermissionFixedAsUser(packageName, permission, overrideSystemFixed, false, + user, context) + && isPermissionAndAppOpGrantedAsUser(packageName, permission, user, context)) { // Stop revoking if this permission is fixed to granted. return false; } if (isForegroundPermission(permission, context)) { String backgroundPermission = getBackgroundPermission(permission, context); - if (isPermissionAndAppOpGranted(packageName, backgroundPermission, context)) { + if (isPermissionAndAppOpGrantedAsUser(packageName, backgroundPermission, user, + context)) { // Stop revoking if this foreground permission has a granted background permission. return false; } } - return revokePermissionAndAppOp(packageName, permission, context); + return revokePermissionAndAppOpAsUser(packageName, permission, user, context); } - private static boolean revokePermissionAndAppOp(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { + private static boolean revokePermissionAndAppOpAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { boolean permissionOrAppOpChanged = false; - boolean isRuntimePermissionsSupported = isRuntimePermissionsSupported(packageName, context); + boolean isRuntimePermissionsSupported = isRuntimePermissionsSupportedAsUser(packageName, + user, context); if (isRuntimePermissionsSupported) { // Revoke the permission. - permissionOrAppOpChanged |= revokePermissionWithoutAppOp(packageName, permission, - context); + permissionOrAppOpChanged |= revokePermissionWithoutAppOpAsUser(packageName, permission, + user, context); } // Revoke the app op. @@ -514,7 +532,8 @@ public class Permissions { // This permission is an ordinary or foreground permission, reset its app op mode to // default. int appOpMode = getDefaultAppOpMode(appOp); - boolean appOpModeChanged = setAppOpUidMode(packageName, appOp, appOpMode, context); + boolean appOpModeChanged = setAppOpUidModeAsUser(packageName, appOp, appOpMode, + user, context); permissionOrAppOpChanged |= appOpModeChanged; if (appOpModeChanged) { @@ -523,9 +542,9 @@ public class Permissions { || appOpMode == AppOpsManager.MODE_ALLOWED)) { // We've reset this permission's app op mode to be permissive, so we'll need // the user to review it again. - setPermissionFlags(packageName, permission, + setPermissionFlagsAsUser(packageName, permission, PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, - PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, context); + PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, user, context); } } } @@ -537,7 +556,8 @@ public class Permissions { for (int i = 0; i < foregroundPermissionsSize; i++) { String foregroundPermission = foregroundPermissions.get(i); - if (!isPermissionAndAppOpGranted(packageName, foregroundPermission, context)) { + if (!isPermissionAndAppOpGrantedAsUser(packageName, foregroundPermission, user, + context)) { continue; } @@ -545,8 +565,8 @@ public class Permissions { if (foregroundAppOp == null) { continue; } - permissionOrAppOpChanged |= setAppOpUidMode(packageName, foregroundAppOp, - AppOpsManager.MODE_FOREGROUND, context); + permissionOrAppOpChanged |= setAppOpUidModeAsUser(packageName, foregroundAppOp, + AppOpsManager.MODE_FOREGROUND, user, context); } } @@ -554,24 +574,25 @@ public class Permissions { } @Nullable - private static PackageInfo getPackageInfo(@NonNull String packageName, - @NonNull Context context) { - return getPackageInfo(packageName, 0, context); + private static PackageInfo getPackageInfoAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + return getPackageInfoAsUser(packageName, 0, user, context); } @Nullable - private static PackageInfo getFactoryPackageInfo(@NonNull String packageName, - @NonNull Context context) { - return getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY, context); + private static PackageInfo getFactoryPackageInfoAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + return getPackageInfoAsUser(packageName, PackageManager.MATCH_FACTORY_ONLY, + user, context); } @Nullable - private static PackageInfo getPackageInfo(@NonNull String packageName, int extraFlags, - @NonNull Context context) { - return PackageUtils.getPackageInfo(packageName, extraFlags + private static PackageInfo getPackageInfoAsUser(@NonNull String packageName, int extraFlags, + @NonNull UserHandle user, @NonNull Context context) { + return PackageUtils.getPackageInfoAsUser(packageName, extraFlags // TODO: Why MATCH_UNINSTALLED_PACKAGES? | PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS, - context); + user, context); } private static boolean isUpdatedSystemApp(@NonNull PackageInfo packageInfo) { @@ -579,27 +600,26 @@ public class Permissions { & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - static boolean isRuntimePermissionsSupported(@NonNull String packageName, - @NonNull Context context) { - ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + static boolean isRuntimePermissionsSupportedAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, + context); if (applicationInfo == null) { return false; } return applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; } - private static int getPermissionFlags(@NonNull String packageName, @NonNull String permission, - @NonNull Context context) { + private static int getPermissionFlagsAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { PackageManager packageManager = context.getPackageManager(); - UserHandle user = Process.myUserHandle(); return packageManager.getPermissionFlags(permission, packageName, user); } - private static boolean isPermissionFixed(@NonNull String packageName, + private static boolean isPermissionFixedAsUser(@NonNull String packageName, @NonNull String permission, boolean overrideSystemFixed, - boolean overrideUserSetAndFixed, @NonNull Context context) { - int flags = getPermissionFlags(packageName, permission, context); + boolean overrideUserSetAndFixed, @NonNull UserHandle user, @NonNull Context context) { + int flags = getPermissionFlagsAsUser(packageName, permission, user, context); int fixedFlags = PackageManager.FLAG_PERMISSION_POLICY_FIXED; if (!overrideSystemFixed) { fixedFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; @@ -611,67 +631,69 @@ public class Permissions { return (flags & fixedFlags) != 0; } - private static boolean isPermissionGrantedByDefault(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { - int flags = getPermissionFlags(packageName, permission, context); + private static boolean isPermissionGrantedByDefaultAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { + int flags = getPermissionFlagsAsUser(packageName, permission, user, context); return (flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0; } - static boolean isPermissionGrantedByRole(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { - int flags = getPermissionFlags(packageName, permission, context); + static boolean isPermissionGrantedByRoleAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { + int flags = getPermissionFlagsAsUser(packageName, permission, user, context); return (flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE) != 0; } - private static boolean isPermissionReviewRequired(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { - int flags = getPermissionFlags(packageName, permission, context); + private static boolean isPermissionReviewRequiredAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { + int flags = getPermissionFlagsAsUser(packageName, permission, user, context); return (flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0; } - private static void setPermissionFlags(@NonNull String packageName, @NonNull String permission, - int flags, int mask, @NonNull Context context) { + private static void setPermissionFlagsAsUser(@NonNull String packageName, + @NonNull String permission, int flags, int mask, @NonNull UserHandle user, + @NonNull Context context) { PackageManager packageManager = context.getPackageManager(); - UserHandle user = Process.myUserHandle(); packageManager.updatePermissionFlags(permission, packageName, mask, flags, user); } - static void setPermissionGrantedByRole(@NonNull String packageName, - @NonNull String permission, boolean grantedByRole, @NonNull Context context) { - setPermissionFlags(packageName, permission, + static void setPermissionGrantedByRoleAsUser(@NonNull String packageName, + @NonNull String permission, boolean grantedByRole, @NonNull UserHandle user, + @NonNull Context context) { + setPermissionFlagsAsUser(packageName, permission, grantedByRole ? PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE : 0, - PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, context); + PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, user, context); } /** * Most of the time {@link #isPermissionAndAppOpGranted(String, String, Context)} should be used * instead. */ - private static boolean isPermissionGrantedWithoutCheckingAppOp(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { - PackageManager packageManager = context.getPackageManager(); - return packageManager.checkPermission(permission, packageName) + private static boolean isPermissionGrantedWithoutCheckingAppOpAsUser( + @NonNull String packageName, @NonNull String permission, @NonNull UserHandle user, + @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); + return userPackageManager.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED; } - private static boolean grantPermissionWithoutAppOp(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { - if (isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) { + private static boolean grantPermissionWithoutAppOpAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { + if (isPermissionGrantedWithoutCheckingAppOpAsUser(packageName, permission, user, context)) { return false; } PackageManager packageManager = context.getPackageManager(); - UserHandle user = Process.myUserHandle(); packageManager.grantRuntimePermission(packageName, permission, user); return true; } - private static boolean revokePermissionWithoutAppOp(@NonNull String packageName, - @NonNull String permission, @NonNull Context context) { - if (!isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) { + private static boolean revokePermissionWithoutAppOpAsUser(@NonNull String packageName, + @NonNull String permission, @NonNull UserHandle user, @NonNull Context context) { + if (!isPermissionGrantedWithoutCheckingAppOpAsUser(packageName, permission, user, + context)) { return false; } PackageManager packageManager = context.getPackageManager(); - UserHandle user = Process.myUserHandle(); packageManager.revokeRuntimePermission(packageName, permission, user); return true; } @@ -816,10 +838,10 @@ public class Permissions { } @Nullable - static Integer getAppOpMode(@NonNull String packageName, @NonNull String appOp, - @NonNull Context context) { + static Integer getAppOpModeAsUser(@NonNull String packageName, @NonNull String appOp, + @NonNull UserHandle user, @NonNull Context context) { ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + user, context); if (applicationInfo == null) { return null; } @@ -831,24 +853,24 @@ public class Permissions { return AppOpsManager.opToDefaultMode(appOp); } - static boolean setAppOpUidMode(@NonNull String packageName, @NonNull String appOp, int mode, - @NonNull Context context) { - return setAppOpMode(packageName, appOp, mode, true, context); + static boolean setAppOpUidModeAsUser(@NonNull String packageName, @NonNull String appOp, + int mode, @NonNull UserHandle user, @NonNull Context context) { + return setAppOpModeAsUser(packageName, appOp, mode, true, user, context); } - static boolean setAppOpPackageMode(@NonNull String packageName, @NonNull String appOp, int mode, - @NonNull Context context) { - return setAppOpMode(packageName, appOp, mode, false, context); + static boolean setAppOpPackageModeAsUser(@NonNull String packageName, @NonNull String appOp, + int mode, @NonNull UserHandle user, @NonNull Context context) { + return setAppOpModeAsUser(packageName, appOp, mode, false, user, context); } - private static boolean setAppOpMode(@NonNull String packageName, @NonNull String appOp, - int mode, boolean setUidMode, @NonNull Context context) { - Integer currentMode = getAppOpMode(packageName, appOp, context); + private static boolean setAppOpModeAsUser(@NonNull String packageName, @NonNull String appOp, + int mode, boolean setUidMode, @NonNull UserHandle user, @NonNull Context context) { + Integer currentMode = getAppOpModeAsUser(packageName, appOp, user, context); if (currentMode != null && currentMode == mode) { return false; } - ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, + context); if (applicationInfo == null) { Log.e(LOG_TAG, "Cannot get ApplicationInfo for package to set app op mode: " + packageName); diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java b/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java index 5b9c22b67..7ea7de046 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/PreferredActivity.java @@ -22,9 +22,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.UserHandle; import androidx.annotation.NonNull; +import com.android.role.controller.util.UserUtils; + import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -67,18 +70,21 @@ public class PreferredActivity { * Configure this preferred activity specification for an application. * * @param packageName the package name of the application + * @param user the user of the application * @param context the {@code Context} to retrieve system services */ - public void configure(@NonNull String packageName, @NonNull Context context) { - ComponentName packageActivity = mActivity.getQualifyingComponentForPackage( - packageName, context); + public void configureAsUser(@NonNull String packageName, @NonNull UserHandle user, + @NonNull Context context) { + ComponentName packageActivity = mActivity.getQualifyingComponentForPackageAsUser( + packageName, user, context); if (packageActivity == null) { // We might be running into some race condition here, but we can't do anything about it. // This should be handled by a future reconciliation started by the package change. return; } - PackageManager packageManager = context.getPackageManager(); + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); int intentFilterDatasSize = mIntentFilterDatas.size(); for (int i = 0; i < intentFilterDatasSize; i++) { IntentFilterData intentFilterData = mIntentFilterDatas.get(i); @@ -92,7 +98,7 @@ public class PreferredActivity { ? IntentFilter.MATCH_CATEGORY_SCHEME : IntentFilter.MATCH_CATEGORY_EMPTY; Intent intent = intentFilterData.createIntent(); - List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, + List<ResolveInfo> resolveInfos = userPackageManager.queryIntentActivities(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DEFAULT_ONLY); @@ -107,7 +113,7 @@ public class PreferredActivity { set.add(componentName); } - packageManager.replacePreferredActivity(intentFilter, match, set, packageActivity); + userPackageManager.replacePreferredActivity(intentFilter, match, set, packageActivity); } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java index 58c878e56..25c97aefb 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredActivity.java @@ -16,12 +16,11 @@ package com.android.role.controller.model; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.Bundle; import android.os.UserHandle; import androidx.annotation.NonNull; @@ -52,11 +51,15 @@ public class RequiredActivity extends RequiredComponent { return userPackageManager.queryIntentActivities(intent, flags); } + @Override + protected boolean isComponentQualified(@NonNull ResolveInfo resolveInfo) { + return resolveInfo.activityInfo.exported; + } + @NonNull @Override - protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) { - return new ComponentName(resolveInfo.activityInfo.packageName, - resolveInfo.activityInfo.name); + protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) { + return resolveInfo.activityInfo; } @Override @@ -69,10 +72,4 @@ public class RequiredActivity extends RequiredComponent { protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) { return resolveInfo.activityInfo.permission; } - - @Nullable - @Override - protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) { - return resolveInfo.activityInfo.metaData; - } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java index 945fda3c3..1e23af256 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredBroadcastReceiver.java @@ -16,12 +16,11 @@ package com.android.role.controller.model; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.Bundle; import android.os.UserHandle; import androidx.annotation.NonNull; @@ -53,9 +52,8 @@ public class RequiredBroadcastReceiver extends RequiredComponent { @NonNull @Override - protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) { - return new ComponentName(resolveInfo.activityInfo.packageName, - resolveInfo.activityInfo.name); + protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) { + return resolveInfo.activityInfo; } @Override @@ -68,10 +66,4 @@ public class RequiredBroadcastReceiver extends RequiredComponent { protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) { return resolveInfo.activityInfo.permission; } - - @Nullable - @Override - protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) { - return resolveInfo.activityInfo.metaData; - } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java index ae6156e7f..6e067488c 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredComponent.java @@ -20,11 +20,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Build; import android.os.Bundle; -import android.os.Process; import android.os.UserHandle; import android.util.ArraySet; @@ -108,9 +108,9 @@ public abstract class RequiredComponent { * @return whether this required component is available */ public boolean isAvailable() { - // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization. - if (mMinTargetSdkVersion >= 34) { - return SdkLevel.isAtLeastU(); + // Workaround to match the value 35+ for V+ in roles.xml before SDK finalization. + if (mMinTargetSdkVersion >= 35) { + return SdkLevel.isAtLeastV(); } else { return Build.VERSION.SDK_INT >= mMinTargetSdkVersion; } @@ -144,15 +144,16 @@ public abstract class RequiredComponent { * Get the component that matches this required component within a package, if any. * * @param packageName the package name for this query + * @param user the user of the component * @param context the {@code Context} to retrieve system services * * @return the matching component, or {@code null} if none. */ @Nullable - public ComponentName getQualifyingComponentForPackage(@NonNull String packageName, - @NonNull Context context) { - List<ComponentName> componentNames = getQualifyingComponentsInternal(packageName, - Process.myUserHandle(), context); + public ComponentName getQualifyingComponentForPackageAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + List<ComponentName> componentNames = getQualifyingComponentsAsUserInternal(packageName, + user, context); return !componentNames.isEmpty() ? componentNames.get(0) : null; } @@ -170,11 +171,11 @@ public abstract class RequiredComponent { @NonNull public List<ComponentName> getQualifyingComponentsAsUser(@NonNull UserHandle user, @NonNull Context context) { - return getQualifyingComponentsInternal(null, user, context); + return getQualifyingComponentsAsUserInternal(null, user, context); } @NonNull - private List<ComponentName> getQualifyingComponentsInternal(@Nullable String packageName, + private List<ComponentName> getQualifyingComponentsAsUserInternal(@Nullable String packageName, @NonNull UserHandle user, @NonNull Context context) { Intent intent = mIntentFilterData.createIntent(); if (packageName != null) { @@ -195,6 +196,10 @@ public abstract class RequiredComponent { for (int resolveInfosIndex = 0; resolveInfosIndex < resolveInfosSize; resolveInfosIndex++) { ResolveInfo resolveInfo = resolveInfos.get(resolveInfosIndex); + if (!isComponentQualified(resolveInfo)) { + continue; + } + if (mFlags != 0) { int componentFlags = getComponentFlags(resolveInfo); if ((componentFlags & mFlags) != mFlags) { @@ -209,8 +214,9 @@ public abstract class RequiredComponent { } } + ComponentInfo componentInfo = getComponentComponentInfo(resolveInfo); if (hasMetaData) { - Bundle componentMetaData = getComponentMetaData(resolveInfo); + Bundle componentMetaData = componentInfo.metaData; if (componentMetaData == null) { componentMetaData = Bundle.EMPTY; } @@ -229,13 +235,14 @@ public abstract class RequiredComponent { } } - ComponentName componentName = getComponentComponentName(resolveInfo); - String componentPackageName = componentName.getPackageName(); + String componentPackageName = componentInfo.packageName; if (componentPackageNames.contains(componentPackageName)) { continue; } - componentPackageNames.add(componentPackageName); + + ComponentName componentName = new ComponentName(componentPackageName, + componentInfo.name); componentNames.add(componentName); } return componentNames; @@ -256,15 +263,19 @@ public abstract class RequiredComponent { protected abstract List<ResolveInfo> queryIntentComponentsAsUser(@NonNull Intent intent, int flags, @NonNull UserHandle user, @NonNull Context context); + protected boolean isComponentQualified(@NonNull ResolveInfo resolveInfo) { + return true; + } + /** - * Get the {@code ComponentName} of a component. + * Get the {@code ComponentInfo} of a component. * * @param resolveInfo the {@code ResolveInfo} of the component * - * @return the {@code ComponentName} of the component + * @return the {@code ComponentInfo} of the component */ @NonNull - protected abstract ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo); + protected abstract ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo); /** * Get the flags that have been set on a component. @@ -285,16 +296,6 @@ public abstract class RequiredComponent { @Nullable protected abstract String getComponentPermission(@NonNull ResolveInfo resolveInfo); - /** - * Get the meta data associated with a component. - * - * @param resolveInfo the {@code ResolveInfo} of the component - * - * @return the meta data associated with a component - */ - @Nullable - protected abstract Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo); - @Override public String toString() { return "RequiredComponent{" diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java index 7b53a25bb..b02062b11 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredContentProvider.java @@ -16,12 +16,11 @@ package com.android.role.controller.model; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.Bundle; import android.os.UserHandle; import androidx.annotation.NonNull; @@ -53,9 +52,8 @@ public class RequiredContentProvider extends RequiredComponent { @NonNull @Override - protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) { - return new ComponentName(resolveInfo.providerInfo.packageName, - resolveInfo.providerInfo.name); + protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) { + return resolveInfo.providerInfo; } @Override @@ -70,10 +68,4 @@ public class RequiredContentProvider extends RequiredComponent { //return resolveInfo.providerInfo.readPermission; throw new UnsupportedOperationException(); } - - @Nullable - @Override - protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) { - return resolveInfo.providerInfo.metaData; - } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java index f27aae013..0532e53b2 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RequiredService.java @@ -16,12 +16,11 @@ package com.android.role.controller.model; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.Bundle; import android.os.UserHandle; import androidx.annotation.NonNull; @@ -53,8 +52,8 @@ public class RequiredService extends RequiredComponent { @NonNull @Override - protected ComponentName getComponentComponentName(@NonNull ResolveInfo resolveInfo) { - return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); + protected ComponentInfo getComponentComponentInfo(@NonNull ResolveInfo resolveInfo) { + return resolveInfo.serviceInfo; } @Override @@ -67,10 +66,4 @@ public class RequiredService extends RequiredComponent { protected String getComponentPermission(@NonNull ResolveInfo resolveInfo) { return resolveInfo.serviceInfo.permission; } - - @Nullable - @Override - protected Bundle getComponentMetaData(@NonNull ResolveInfo resolveInfo) { - return resolveInfo.serviceInfo.metaData; - } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java index 9ff16db0f..6c7eb7d9e 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/Role.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/Role.java @@ -26,7 +26,6 @@ import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; import android.content.res.Resources; import android.os.Build; -import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; @@ -360,11 +359,12 @@ public class Role { /** * Callback when this role is added to the system for the first time. * + * @param user the user to add the role for * @param context the {@code Context} to retrieve system services */ - public void onRoleAdded(@NonNull Context context) { + public void onRoleAddedAsUser(@NonNull UserHandle user, @NonNull Context context) { if (mBehavior != null) { - mBehavior.onRoleAdded(this, context); + mBehavior.onRoleAddedAsUser(this, user, context); } } @@ -392,26 +392,15 @@ public class Role { * @return whether this role is available based on SDK version */ boolean isAvailableBySdkVersion() { - // Workaround to match the value 34+ for U+ in roles.xml before SDK finalization. - if (mMinSdkVersion >= 34) { - return SdkLevel.isAtLeastU(); + // Workaround to match the value 35+ for V+ in roles.xml before SDK finalization. + if (mMinSdkVersion >= 35) { + return SdkLevel.isAtLeastV(); } else { return Build.VERSION.SDK_INT >= mMinSdkVersion && Build.VERSION.SDK_INT <= mMaxSdkVersion; } } - /** - * Check whether this role is available, for current user. - * - * @param context the {@code Context} to retrieve system services - * - * @return whether this role is available. - */ - public boolean isAvailable(@NonNull Context context) { - return isAvailableAsUser(Process.myUserHandle(), context); - } - public boolean isStatic() { return mStatic; } @@ -420,15 +409,16 @@ public class Role { * Get the default holders of this role, which will be added when the role is added for the * first time. * + * @param user the user of the role * @param context the {@code Context} to retrieve system services - * * @return the list of package names of the default holders */ @NonNull - public List<String> getDefaultHolders(@NonNull Context context) { + public List<String> getDefaultHoldersAsUser(@NonNull UserHandle user, + @NonNull Context context) { if (mDefaultHoldersResourceName == null) { if (mBehavior != null) { - return mBehavior.getDefaultHolders(this, context); + return mBehavior.getDefaultHoldersAsUser(this, user, context); } return Collections.emptyList(); } @@ -454,7 +444,8 @@ public class Role { } if (isExclusive()) { - String packageName = getQualifiedDefaultHolderPackageName(defaultHolders, context); + String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolders, user, + context); if (packageName == null) { return Collections.emptyList(); } @@ -462,7 +453,8 @@ public class Role { } else { List<String> packageNames = new ArrayList<>(); for (String defaultHolder : defaultHolders.split(DEFAULT_HOLDER_SEPARATOR)) { - String packageName = getQualifiedDefaultHolderPackageName(defaultHolder, context); + String packageName = getQualifiedDefaultHolderPackageNameAsUser(defaultHolder, + user, context); if (packageName != null) { packageNames.add(packageName); } @@ -472,8 +464,8 @@ public class Role { } @Nullable - private String getQualifiedDefaultHolderPackageName(@NonNull String defaultHolder, - @NonNull Context context) { + private String getQualifiedDefaultHolderPackageNameAsUser(@NonNull String defaultHolder, + @NonNull UserHandle user, @NonNull Context context) { String packageName; byte[] certificate; int certificateSeparatorIndex = defaultHolder.indexOf(CERTIFICATE_SEPARATOR); @@ -492,8 +484,9 @@ public class Role { } if (certificate != null) { - PackageManager packageManager = context.getPackageManager(); - if (!packageManager.hasSigningCertificate(packageName, certificate, + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); + if (!userPackageManager.hasSigningCertificate(packageName, certificate, PackageManager.CERT_INPUT_SHA256)) { Log.w(LOG_TAG, "Default holder doesn't have required signing certificate: " + defaultHolder); @@ -501,7 +494,7 @@ public class Role { } } else { ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + user, context); if (applicationInfo == null) { Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName); return null; @@ -521,20 +514,20 @@ public class Role { * <p> * Should return {@code null} if this role {@link #mShowNone shows a "None" item}. * + * @param user the user of the role * @param context the {@code Context} to retrieve system services - * * @return the package name of the fallback holder, or {@code null} if none */ @Nullable - public String getFallbackHolder(@NonNull Context context) { - if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, Process.myUserHandle(), context)) { + public String getFallbackHolderAsUser(@NonNull UserHandle user, @NonNull Context context) { + if (!RoleManagerCompat.isRoleFallbackEnabledAsUser(this, user, context)) { return null; } if (mFallBackToDefaultHolder) { - return CollectionUtils.firstOrNull(getDefaultHolders(context)); + return CollectionUtils.firstOrNull(getDefaultHoldersAsUser(user, context)); } if (mBehavior != null) { - return mBehavior.getFallbackHolder(this, context); + return mBehavior.getFallbackHolderAsUser(this, user, context); } return null; } @@ -562,29 +555,32 @@ public class Role { * components (plus meeting some other general restrictions). * * @param packageName the package name to check for + * @param user the user to check for * @param context the {@code Context} to retrieve system services * * @return whether the package is qualified for a role */ - public boolean isPackageQualified(@NonNull String packageName, @NonNull Context context) { + public boolean isPackageQualifiedAsUser(@NonNull String packageName, @NonNull UserHandle user, + @NonNull Context context) { RoleManager roleManager = context.getSystemService(RoleManager.class); if (shouldAllowBypassingQualification(context) && RoleManagerCompat.isBypassingRoleQualification(roleManager)) { return true; } - ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, + context); if (applicationInfo == null) { Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName); return false; } - if (!isPackageMinimallyQualifiedAsUser(applicationInfo, Process.myUserHandle(), context)) { + if (!isPackageMinimallyQualifiedAsUser(applicationInfo, user, context)) { return false; } if (mBehavior != null) { - Boolean isPackageQualified = mBehavior.isPackageQualified(this, packageName, context); + Boolean isPackageQualified = mBehavior.isPackageQualifiedAsUser(this, packageName, + user, context); if (isPackageQualified != null) { return isPackageQualified; } @@ -598,14 +594,15 @@ public class Role { continue; } - if (requiredComponent.getQualifyingComponentForPackage(packageName, context) == null) { + if (requiredComponent.getQualifyingComponentForPackageAsUser(packageName, user, context) + == null) { Log.i(LOG_TAG, packageName + " not qualified for " + mName + " due to missing " + requiredComponent); return false; } } - if (mStatic && !getDefaultHolders(context).contains(packageName)) { + if (mStatic && !getDefaultHoldersAsUser(user, context).contains(packageName)) { return false; } @@ -778,41 +775,42 @@ public class Role { * @param packageName the package name of the application to be granted this role to * @param dontKillApp whether this application should not be killed despite changes * @param overrideUser whether to override user when granting privileges + * @param user the user of the application * @param context the {@code Context} to retrieve system services */ - public void grant(@NonNull String packageName, boolean dontKillApp, - boolean overrideUser, @NonNull Context context) { - boolean permissionOrAppOpChanged = Permissions.grant(packageName, + public void grantAsUser(@NonNull String packageName, boolean dontKillApp, + boolean overrideUser, @NonNull UserHandle user, @NonNull Context context) { + boolean permissionOrAppOpChanged = Permissions.grantAsUser(packageName, Permissions.filterBySdkVersion(mPermissions), SdkLevel.isAtLeastS() ? !mSystemOnly : true, overrideUser, true, false, false, - context); + user, context); List<String> appOpPermissionsToGrant = Permissions.filterBySdkVersion(mAppOpPermissions); int appOpPermissionsSize = appOpPermissionsToGrant.size(); for (int i = 0; i < appOpPermissionsSize; i++) { String appOpPermission = appOpPermissionsToGrant.get(i); - AppOpPermissions.grant(packageName, appOpPermission, overrideUser, context); + AppOpPermissions.grantAsUser(packageName, appOpPermission, overrideUser, user, context); } int appOpsSize = mAppOps.size(); for (int i = 0; i < appOpsSize; i++) { AppOp appOp = mAppOps.get(i); - appOp.grant(packageName, context); + appOp.grantAsUser(packageName, user, context); } int preferredActivitiesSize = mPreferredActivities.size(); for (int i = 0; i < preferredActivitiesSize; i++) { PreferredActivity preferredActivity = mPreferredActivities.get(i); - preferredActivity.configure(packageName, context); + preferredActivity.configureAsUser(packageName, user, context); } if (mBehavior != null) { - mBehavior.grant(this, packageName, context); + mBehavior.grantAsUser(this, packageName, user, context); } - if (!dontKillApp && permissionOrAppOpChanged && !Permissions.isRuntimePermissionsSupported( - packageName, context)) { - killApp(packageName, context); + if (!dontKillApp && permissionOrAppOpChanged + && !Permissions.isRuntimePermissionsSupportedAsUser(packageName, user, context)) { + killAppAsUser(packageName, user, context); } } @@ -822,12 +820,15 @@ public class Role { * @param packageName the package name of the application to be granted this role to * @param dontKillApp whether this application should not be killed despite changes * @param overrideSystemFixedPermissions whether system-fixed permissions can be revoked + * @param user the user of the role * @param context the {@code Context} to retrieve system services */ - public void revoke(@NonNull String packageName, boolean dontKillApp, - boolean overrideSystemFixedPermissions, @NonNull Context context) { - RoleManager roleManager = context.getSystemService(RoleManager.class); - List<String> otherRoleNames = roleManager.getHeldRolesFromController(packageName); + public void revokeAsUser(@NonNull String packageName, boolean dontKillApp, + boolean overrideSystemFixedPermissions, @NonNull UserHandle user, + @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + RoleManager userRoleManager = userContext.getSystemService(RoleManager.class); + List<String> otherRoleNames = userRoleManager.getHeldRolesFromController(packageName); otherRoleNames.remove(mName); List<String> permissionsToRevoke = Permissions.filterBySdkVersion(mPermissions); @@ -839,8 +840,8 @@ public class Role { permissionsToRevoke.removeAll(Permissions.filterBySdkVersion(role.mPermissions)); } - boolean permissionOrAppOpChanged = Permissions.revoke(packageName, permissionsToRevoke, - true, false, overrideSystemFixedPermissions, context); + boolean permissionOrAppOpChanged = Permissions.revokeAsUser(packageName, + permissionsToRevoke, true, false, overrideSystemFixedPermissions, user, context); List<String> appOpPermissionsToRevoke = Permissions.filterBySdkVersion(mAppOpPermissions); for (int i = 0; i < otherRoleNamesSize; i++) { @@ -852,7 +853,7 @@ public class Role { int appOpPermissionsSize = appOpPermissionsToRevoke.size(); for (int i = 0; i < appOpPermissionsSize; i++) { String appOpPermission = appOpPermissionsToRevoke.get(i); - AppOpPermissions.revoke(packageName, appOpPermission, context); + AppOpPermissions.revokeAsUser(packageName, appOpPermission, user, context); } List<AppOp> appOpsToRevoke = new ArrayList<>(mAppOps); @@ -864,7 +865,7 @@ public class Role { int appOpsSize = appOpsToRevoke.size(); for (int i = 0; i < appOpsSize; i++) { AppOp appOp = appOpsToRevoke.get(i); - appOp.revoke(packageName, context); + appOp.revokeAsUser(packageName, user, context); } // TODO: Revoke preferred activities? But this is unnecessary for most roles using it as @@ -873,22 +874,23 @@ public class Role { // wrong thing when we are removing a exclusive role holder for adding another. if (mBehavior != null) { - mBehavior.revoke(this, packageName, context); + mBehavior.revokeAsUser(this, packageName, user, context); } if (!dontKillApp && permissionOrAppOpChanged) { - killApp(packageName, context); + killAppAsUser(packageName, user, context); } } - private void killApp(@NonNull String packageName, @NonNull Context context) { + private void killAppAsUser(@NonNull String packageName, @NonNull UserHandle user, + @NonNull Context context) { if (DEBUG) { Log.i(LOG_TAG, "Killing " + packageName + " due to " + Thread.currentThread().getStackTrace()[3].getMethodName() + "(" + mName + ")"); } - ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, - Process.myUserHandle(), context); + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, user, + context); if (applicationInfo == null) { Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName); return; @@ -947,6 +949,40 @@ public class Role { RoleManagerCompat.setRoleFallbackEnabledAsUser(this, false, user, context); } + /** + * Check whether this role should be visible to user. + * + * @param user the user to check for + * @param context the `Context` to retrieve system services + * + * @return whether this role should be visible to user + */ + public boolean isVisibleAsUser(@NonNull UserHandle user, @NonNull Context context) { + RoleBehavior behavior = getBehavior(); + if (behavior == null) { + return isVisible(); + } + return isVisible() && behavior.isVisibleAsUser(this, user, context); + } + + /** + * Check whether a qualifying application should be visible to user. + * + * @param applicationInfo the {@link ApplicationInfo} for the application + * @param user the user for the application + * @param context the {@code Context} to retrieve system services + * + * @return whether the qualifying application should be visible to user + */ + public boolean isApplicationVisibleAsUser(@NonNull ApplicationInfo applicationInfo, + @NonNull UserHandle user, @NonNull Context context) { + RoleBehavior behavior = getBehavior(); + if (behavior == null) { + return true; + } + return behavior.isApplicationVisibleAsUser(this, applicationInfo, user, context); + } + @Override public String toString() { return "Role{" diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java index f0c4fc018..4bc1873d5 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleBehavior.java @@ -17,6 +17,7 @@ package com.android.role.controller.model; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.os.UserHandle; import androidx.annotation.NonNull; @@ -31,9 +32,10 @@ import java.util.List; public interface RoleBehavior { /** - * @see Role#onRoleAdded(Context) + * @see Role#onRoleAddedAsUser(UserHandle, Context) */ - default void onRoleAdded(@NonNull Role role, @NonNull Context context) {} + default void onRoleAddedAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) {} /** * @see Role#isAvailableAsUser(UserHandle, Context) @@ -47,7 +49,8 @@ public interface RoleBehavior { * @see Role#getDefaultHolders(Context) */ @NonNull - default List<String> getDefaultHolders(@NonNull Role role, @NonNull Context context) { + default List<String> getDefaultHoldersAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { return Collections.emptyList(); } @@ -55,7 +58,8 @@ public interface RoleBehavior { * @see Role#getFallbackHolder(Context) */ @Nullable - default String getFallbackHolder(@NonNull Role role, @NonNull Context context) { + default String getFallbackHolderAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { return null; } @@ -72,8 +76,8 @@ public interface RoleBehavior { * @see Role#isPackageQualified(String, Context) */ @Nullable - default Boolean isPackageQualified(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) { + default Boolean isPackageQualifiedAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { return null; } @@ -87,15 +91,16 @@ public interface RoleBehavior { } /** - * @see Role#grant(String, boolean, boolean, boolean, Context) + * @see Role#grantAsUser(String, boolean, boolean, UserHandle, Context) */ - default void grant(@NonNull Role role, @NonNull String packageName, @NonNull Context context) {} + default void grantAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) {} /** - * @see Role#revoke(String, boolean, boolean, Context) + * @see Role#revokeAsUser(String, boolean, boolean, UserHandle, Context) */ - default void revoke(@NonNull Role role, @NonNull String packageName, - @NonNull Context context) {} + default void revokeAsUser(@NonNull Role role, @NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) {} /** * @see Role#onHolderSelectedAsUser(String, UserHandle, Context) @@ -108,4 +113,34 @@ public interface RoleBehavior { */ default void onHolderChangedAsUser(@NonNull Role role, @NonNull UserHandle user, @NonNull Context context) {} + + /** + * Check whether this role should be visible to user. + * + * @param role the role to check for + * @param user the user to check for + * @param context the `Context` to retrieve system services + * + * @return whether this role should be visible to user + */ + default boolean isVisibleAsUser(@NonNull Role role, @NonNull UserHandle user, + @NonNull Context context) { + return true; + } + + /** + * Check whether a qualifying application should be visible to user. + * + * @param role the role to check for + * @param applicationInfo the {@link ApplicationInfo} for the application + * @param user the user for the application + * @param context the {@code Context} to retrieve system services + * + * @return whether the qualifying application should be visible to user + */ + default boolean isApplicationVisibleAsUser(@NonNull Role role, + @NonNull ApplicationInfo applicationInfo, @NonNull UserHandle user, + @NonNull Context context) { + return true; + } } diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java index 23299419e..cc2d102c8 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java +++ b/PermissionController/role-controller/java/com/android/role/controller/model/RoleParser.java @@ -21,8 +21,10 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; +import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.os.Build; +import android.permission.flags.Flags; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -31,7 +33,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.modules.utils.build.SdkLevel; import com.android.role.controller.behavior.BrowserRoleBehavior; +import com.android.role.controller.util.ResourceUtils; import org.xmlpull.v1.XmlPullParserException; @@ -149,7 +153,7 @@ public class RoleParser { */ @NonNull public ArrayMap<String, Role> parse() { - try (XmlResourceParser parser = sGetRolesXml.apply(mContext)) { + try (XmlResourceParser parser = getRolesXml()) { Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> xml = parseXml(parser); if (xml == null) { return new ArrayMap<>(); @@ -164,6 +168,20 @@ public class RoleParser { } } + /** + * Retrieves the roles.xml resource from a context + */ + private XmlResourceParser getRolesXml() { + if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) { + Resources resources = ResourceUtils.getPermissionControllerResources(mContext); + int resourceId = resources.getIdentifier("roles", "xml", + ResourceUtils.RESOURCE_PACKAGE_NAME_PERMISSION_CONTROLLER); + return resources.getXml(resourceId); + } else { + return sGetRolesXml.apply(mContext); + } + } + @Nullable private Pair<ArrayMap<String, PermissionSet>, ArrayMap<String, Role>> parseXml( @NonNull XmlResourceParser parser) throws IOException, XmlPullParserException { @@ -252,6 +270,9 @@ public class RoleParser { return null; } + int minSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_SDK_VERSION, + Build.VERSION_CODES.BASE); + List<Permission> permissions = new ArrayList<>(); int type; @@ -269,6 +290,8 @@ public class RoleParser { if (permission == null) { continue; } + int mergedMinSdkVersion = Math.max(permission.getMinSdkVersion(), minSdkVersion); + permission = permission.withMinSdkVersion(mergedMinSdkVersion); validateNoDuplicateElement(permission, permissions, "permission"); permissions.add(permission); } else { @@ -738,13 +761,24 @@ public class RoleParser { if (permissionSetName == null) { continue; } - if (!permissionSets.containsKey(permissionSetName)) { + PermissionSet permissionSet = permissionSets.get(permissionSetName); + if (permissionSet == null) { throwOrLogMessage("Unknown permission set:" + permissionSetName); continue; } - PermissionSet permissionSet = permissionSets.get(permissionSetName); - // We do allow intersection between permission sets. - permissions.addAll(permissionSet.getPermissions()); + int minSdkVersion = getAttributeIntValue(parser, ATTRIBUTE_MIN_SDK_VERSION, + Build.VERSION_CODES.BASE); + List<Permission> permissionsInSet = permissionSet.getPermissions(); + int permissionsInSetSize = permissionsInSet.size(); + for (int permissionsInSetIndex = 0; + permissionsInSetIndex < permissionsInSetSize; permissionsInSetIndex++) { + Permission permission = permissionsInSet.get(permissionsInSetIndex); + int mergedMinSdkVersion = + Math.max(permission.getMinSdkVersion(), minSdkVersion); + permission = permission.withMinSdkVersion(mergedMinSdkVersion); + // We do allow intersection between permission sets. + permissions.add(permission); + } break; } case TAG_PERMISSION: { diff --git a/PermissionController/role-controller/java/com/android/role/controller/model/VisibilityMixin.java b/PermissionController/role-controller/java/com/android/role/controller/model/VisibilityMixin.java new file mode 100644 index 000000000..fdfb45143 --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/model/VisibilityMixin.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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.role.controller.model; + +import android.content.Context; +import android.content.res.Resources; +import android.os.UserHandle; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.android.role.controller.util.ResourceUtils; + +/** + * Mixin for {@link RoleBehavior#isVisibleAsUser(Role, UserHandle, Context)} that returns whether + * the role should be visible from a corresponding boolean resource. + */ +public class VisibilityMixin { + + private static final String LOG_TAG = VisibilityMixin.class.getSimpleName(); + + private VisibilityMixin() {} + + /** + * Get the boolean resource value that represents whether a role is visible to the user. + * + * @param resourceName the name of the resource + * @param isPermissionControllerResource if {@code true}, and if the current SDK level is at + * least V, get the resource from a PermissionController context for the given user. + * Otherwise, get the resource the provided context. + * @param user the user to get the PermissionController context for + * @param context the `Context` to retrieve the resource (and system services) + * + * @return whether this role should be visible to user + */ + public static boolean isVisible(@NonNull String resourceName, + boolean isPermissionControllerResource, @NonNull UserHandle user, + @NonNull Context context) { + Resources resources = isPermissionControllerResource + ? ResourceUtils.getPermissionControllerResources(context) : context.getResources(); + String packageName = isPermissionControllerResource + ? ResourceUtils.RESOURCE_PACKAGE_NAME_PERMISSION_CONTROLLER : "android"; + + int resourceId = resources.getIdentifier(resourceName, "bool", packageName); + if (resourceId == 0) { + Log.w(LOG_TAG, "Cannot find resource for visibility: " + resourceName); + return true; + } + try { + return resources.getBoolean(resourceId); + } catch (Resources.NotFoundException e) { + Log.w(LOG_TAG, "Cannot get resource for visibility: " + resourceName, e); + return true; + } + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java new file mode 100644 index 000000000..2a6010c4d --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2018 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.role.controller.service; + +import android.app.role.RoleControllerService; +import android.app.role.RoleManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Process; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.WorkerThread; + +import com.android.role.controller.model.Role; +import com.android.role.controller.model.Roles; +import com.android.role.controller.util.CollectionUtils; +import com.android.role.controller.util.LegacyRoleFallbackEnabledUtils; +import com.android.role.controller.util.PackageUtils; +import com.android.role.controller.util.UserUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Implementation of {@link RoleControllerService}. + */ +public class RoleControllerServiceImpl extends RoleControllerService { + + private static final String LOG_TAG = RoleControllerServiceImpl.class.getSimpleName(); + + private static final boolean DEBUG = false; + + + private UserHandle mUser; + private Context mContext; + private RoleManager mUserRoleManager; + + public RoleControllerServiceImpl() {} + + public RoleControllerServiceImpl(@NonNull UserHandle user, @NonNull Context context) { + init(user, context); + } + + @Override + public void onCreate() { + super.onCreate(); + + init(Process.myUserHandle(), this); + } + + private void init(@NonNull UserHandle user, @NonNull Context context) { + mUser = user; + mContext = context; + Context userContext = UserUtils.getUserContext(context, user); + mUserRoleManager = userContext.getSystemService(RoleManager.class); + } + + @Override + @WorkerThread + public boolean onGrantDefaultRoles() { + if (DEBUG) { + Log.i(LOG_TAG, "Granting default roles, user: " + mUser.myUserId()); + } + + // Gather the available roles for current user. + ArrayMap<String, Role> roleMap = Roles.get(mContext); + List<Role> roles = new ArrayList<>(); + List<String> roleNames = new ArrayList<>(); + ArraySet<String> addedRoleNames = new ArraySet<>(); + int roleMapSize = roleMap.size(); + for (int i = 0; i < roleMapSize; i++) { + Role role = roleMap.valueAt(i); + + if (!role.isAvailableAsUser(mUser, mContext)) { + continue; + } + roles.add(role); + String roleName = role.getName(); + roleNames.add(roleName); + if (!mUserRoleManager.isRoleAvailable(roleName)) { + addedRoleNames.add(roleName); + } + } + + // TODO: Clean up holders of roles that will be removed. + + // Set the available role names in RoleManager. + mUserRoleManager.setRoleNamesFromController(roleNames); + + int addedRoleNamesSize = addedRoleNames.size(); + for (int i = 0; i < addedRoleNamesSize; i++) { + String roleName = addedRoleNames.valueAt(i); + + Role role = roleMap.get(roleName); + role.onRoleAddedAsUser(mUser, mContext); + } + + // Go through the holders of all roles. + int rolesSize = roles.size(); + for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) { + Role role = roles.get(rolesIndex); + + String roleName = role.getName(); + + // For each of the current holders, check if it is still qualified, redo grant if so, or + // remove it otherwise. + List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName); + int currentPackageNamesSize = currentPackageNames.size(); + for (int currentPackageNamesIndex = 0; + currentPackageNamesIndex < currentPackageNamesSize; + currentPackageNamesIndex++) { + String packageName = currentPackageNames.get(currentPackageNamesIndex); + + if (role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { + // We should not override user set or fixed permissions because we are only + // redoing the grant here. Otherwise, user won't be able to revoke permissions + // granted by role. + addRoleHolderInternal(role, packageName, false, false, true); + } else { + Log.i(LOG_TAG, "Removing package that no longer qualifies for the role," + + " package: " + packageName + ", role: " + roleName); + removeRoleHolderInternal(role, packageName, false); + } + } + + // If there is no holder for a role now, or the role is static, we need to add default + // or fallback holders, if any. + currentPackageNames = mUserRoleManager.getRoleHolders(roleName); + currentPackageNamesSize = currentPackageNames.size(); + boolean isStaticRole = role.isStatic(); + if (currentPackageNamesSize == 0 || isStaticRole) { + List<String> packageNamesToAdd = null; + if (addedRoleNames.contains(roleName) || isStaticRole) { + packageNamesToAdd = role.getDefaultHoldersAsUser(mUser, mContext); + } + if (packageNamesToAdd == null || packageNamesToAdd.isEmpty()) { + packageNamesToAdd = CollectionUtils.singletonOrEmpty( + role.getFallbackHolderAsUser(mUser, mContext)); + } + + int packageNamesToAddSize = packageNamesToAdd.size(); + for (int packageNamesToAddIndex = 0; packageNamesToAddIndex < packageNamesToAddSize; + packageNamesToAddIndex++) { + String packageName = packageNamesToAdd.get(packageNamesToAddIndex); + + if (currentPackageNames.contains(packageName)) { + // This may happen when we are ensuring all default holders are added for + // static roles. + continue; + } + if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { + Log.e(LOG_TAG, "Default/fallback role holder package doesn't qualify for" + + " the role, package: " + packageName + ", role: " + roleName); + continue; + } + Log.i(LOG_TAG, "Adding package as default/fallback role holder, package: " + + packageName + ", role: " + roleName); + // TODO: If we don't override user here, user might end up missing incoming + // phone calls or SMS, so we just keep the old behavior. But overriding user + // choice about permission without explicit user action is bad, so maybe we + // should at least show a notification? + addRoleHolderInternal(role, packageName, role.shouldOverrideUserWhenGranting()); + } + } + + // Ensure that an exclusive role has at most one holder. + currentPackageNames = mUserRoleManager.getRoleHolders(roleName); + currentPackageNamesSize = currentPackageNames.size(); + if (role.isExclusive() && currentPackageNamesSize > 1) { + Log.w(LOG_TAG, "Multiple packages holding an exclusive role, role: " + + roleName); + // No good way to determine who should be the only one, just keep the first one. + for (int currentPackageNamesIndex = 1; + currentPackageNamesIndex < currentPackageNamesSize; + currentPackageNamesIndex++) { + String packageName = currentPackageNames.get(currentPackageNamesIndex); + + Log.i(LOG_TAG, "Removing extraneous package for an exclusive role, package: " + + packageName + ", role: " + roleName); + removeRoleHolderInternal(role, packageName, false); + } + } + } + + return true; + } + + @Override + @WorkerThread + public boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName, + int flags) { + if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { + return false; + } + + Role role = Roles.get(mContext).get(roleName); + if (role == null) { + Log.e(LOG_TAG, "Unknown role: " + roleName); + return false; + } + if (!role.isAvailableAsUser(mUser, mContext)) { + Log.e(LOG_TAG, "Role is unavailable: " + roleName); + return false; + } + + if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { + Log.e(LOG_TAG, "Package does not qualify for the role, package: " + packageName + + ", role: " + roleName); + return false; + } + + boolean added = false; + if (role.isExclusive()) { + List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName); + int currentPackageNamesSize = currentPackageNames.size(); + for (int i = 0; i < currentPackageNamesSize; i++) { + String currentPackageName = currentPackageNames.get(i); + + if (Objects.equals(currentPackageName, packageName)) { + Log.i(LOG_TAG, "Package is already a role holder, package: " + packageName + + ", role: " + roleName); + added = true; + continue; + } + + boolean removed = removeRoleHolderInternal(role, currentPackageName, false); + if (!removed) { + // TODO: Clean up? + return false; + } + } + } + + boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); + added = addRoleHolderInternal(role, packageName, dontKillApp, + role.shouldOverrideUserWhenGranting(), added); + if (!added) { + return false; + } + + role.onHolderAddedAsUser(packageName, mUser, mContext); + role.onHolderChangedAsUser(mUser, mContext); + + return true; + } + + @Override + @WorkerThread + public boolean onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName, + int flags) { + if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { + return false; + } + + Role role = Roles.get(mContext).get(roleName); + if (role == null) { + Log.e(LOG_TAG, "Unknown role: " + roleName); + return false; + } + if (!role.isAvailableAsUser(mUser, mContext)) { + Log.e(LOG_TAG, "Role is unavailable: " + roleName); + return false; + } + + boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); + boolean removed = removeRoleHolderInternal(role, packageName, dontKillApp); + if (!removed) { + return false; + } + + // TODO: Should we consider this successful regardless? + boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); + if (!fallbackSuccessful) { + return false; + } + + role.onHolderChangedAsUser(mUser, mContext); + + return true; + } + + @Override + @WorkerThread + public boolean onClearRoleHolders(@NonNull String roleName, int flags) { + if (!checkFlags(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP)) { + return false; + } + + Role role = Roles.get(mContext).get(roleName); + if (role == null) { + Log.e(LOG_TAG, "Unknown role: " + roleName); + return false; + } + if (!role.isAvailableAsUser(mUser, mContext)) { + Log.e(LOG_TAG, "Role is unavailable: " + roleName); + return false; + } + + boolean dontKillApp = hasFlag(flags, RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP); + boolean cleared = clearRoleHoldersInternal(role, dontKillApp); + if (!cleared) { + return false; + } + + // TODO: Should we consider this successful regardless? + boolean fallbackSuccessful = addFallbackRoleHolderMaybe(role); + if (!fallbackSuccessful) { + return false; + } + + role.onHolderChangedAsUser(mUser, mContext); + + return true; + } + + @WorkerThread + private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName, + boolean overrideUser) { + return addRoleHolderInternal(role, packageName, false, overrideUser, false); + } + + @WorkerThread + private boolean addRoleHolderInternal(@NonNull Role role, @NonNull String packageName, + boolean dontKillApp, boolean overrideUser, boolean added) { + role.grantAsUser(packageName, dontKillApp, overrideUser, mUser, mContext); + + String roleName = role.getName(); + if (!added) { + added = mUserRoleManager.addRoleHolderFromController(roleName, packageName); + } + if (!added) { + Log.e(LOG_TAG, "Failed to add role holder in RoleManager, package: " + packageName + + ", role: " + roleName); + } + return added; + } + + @WorkerThread + private boolean removeRoleHolderInternal(@NonNull Role role, @NonNull String packageName, + boolean dontKillApp) { + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, + mUser, mContext); + if (applicationInfo == null) { + Log.w(LOG_TAG, "Cannot get ApplicationInfo for package: " + packageName); + } + + if (applicationInfo != null) { + role.revokeAsUser(packageName, dontKillApp, false, mUser, mContext); + } + + String roleName = role.getName(); + boolean removed = mUserRoleManager.removeRoleHolderFromController(roleName, packageName); + if (!removed) { + Log.e(LOG_TAG, "Failed to remove role holder in RoleManager," + " package: " + + packageName + ", role: " + roleName); + } + return removed; + } + + @WorkerThread + private boolean clearRoleHoldersInternal(@NonNull Role role, boolean dontKillApp) { + String roleName = role.getName(); + List<String> packageNames = mUserRoleManager.getRoleHolders(roleName); + boolean cleared = true; + + int packageNamesSize = packageNames.size(); + for (int i = 0; i < packageNamesSize; i++) { + String packageName = packageNames.get(i); + boolean removed = removeRoleHolderInternal(role, packageName, dontKillApp); + if (!removed) { + cleared = false; + } + } + + if (!cleared) { + Log.e(LOG_TAG, "Failed to clear role holders, role: " + roleName); + } + return cleared; + } + + @WorkerThread + private boolean addFallbackRoleHolderMaybe(@NonNull Role role) { + String roleName = role.getName(); + List<String> currentPackageNames = mUserRoleManager.getRoleHolders(roleName); + if (!currentPackageNames.isEmpty()) { + return true; + } + + String fallbackPackageName = role.getFallbackHolderAsUser(mUser, mContext); + if (fallbackPackageName == null) { + return true; + } + + if (!role.isPackageQualifiedAsUser(fallbackPackageName, mUser, mContext)) { + Log.e(LOG_TAG, "Fallback role holder package doesn't qualify for the role, package: " + + fallbackPackageName + ", role: " + roleName); + return false; + } + + Log.i(LOG_TAG, "Adding package as fallback role holder, package: " + fallbackPackageName + + ", role: " + roleName); + // TODO: If we don't override user here, user might end up missing incoming + // phone calls or SMS, so we just keep the old behavior. But overriding user + // choice about permission without explicit user action is bad, so maybe we + // should at least show a notification? + return addRoleHolderInternal(role, fallbackPackageName, + role.shouldOverrideUserWhenGranting()); + } + + @Override + public boolean onIsApplicationQualifiedForRole(@NonNull String roleName, + @NonNull String packageName) { + // This API has been deprecated and Settings has been using onIsApplicationVisibleForRole() + // instead. + return false; + } + + @Override + public boolean onIsApplicationVisibleForRole(@NonNull String roleName, + @NonNull String packageName) { + Role role = Roles.get(mContext).get(roleName); + if (role == null) { + return false; + } + if (!role.isAvailableAsUser(mUser, mContext)) { + return false; + } + if (!role.isPackageQualifiedAsUser(packageName, mUser, mContext)) { + return false; + } + ApplicationInfo applicationInfo = PackageUtils.getApplicationInfoAsUser(packageName, + mUser, mContext); + if (applicationInfo == null || !role.isApplicationVisibleAsUser(applicationInfo, mUser, + mContext)) { + return false; + } + return true; + } + + @Override + public boolean onIsRoleVisible(@NonNull String roleName) { + Role role = Roles.get(mContext).get(roleName); + if (role == null) { + return false; + } + if (!role.isAvailableAsUser(mUser, mContext)) { + return false; + } + + return role.isVisibleAsUser(mUser, mContext); + } + + @Override + @NonNull + public List<String> onGetLegacyFallbackDisabledRoles() { + return LegacyRoleFallbackEnabledUtils.getFallbackDisabledRoles(mUser, mContext); + } + + + private static boolean checkFlags(int flags, int allowedFlags) { + if ((flags & allowedFlags) != flags) { + Log.e(LOG_TAG, "flags is invalid, flags: 0x" + Integer.toHexString(flags) + + ", allowed flags: 0x" + Integer.toHexString(allowedFlags)); + return false; + } + return true; + } + + private static boolean hasFlag(int flags, int flag) { + return (flags & flag) == flag; + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java new file mode 100644 index 000000000..5be10a26a --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java @@ -0,0 +1,107 @@ +/* + * 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.role.controller.util; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.UserHandle; + +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.List; + +public class LegacyRoleFallbackEnabledUtils { + /** + * Name of generic shared preferences file. + */ + private static final String PREFERENCES_FILE = "preferences"; + + /** + * Key in the generic shared preferences that stores if the user manually selected the "none" + * role holder for a role. + */ + private static final String IS_NONE_ROLE_HOLDER_SELECTED_KEY = "is_none_role_holder_selected:"; + + /** + * Get a device protected storage based shared preferences. Avoid storing sensitive data in it. + * + * @param context the context to get the shared preferences + * @return a device protected storage based shared preferences + */ + @NonNull + @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + private static SharedPreferences getSharedPreferences(@NonNull UserHandle user, + @NonNull Context context) { + String packageName = context.getPackageManager().getPermissionControllerPackageName(); + try { + context = context.createPackageContextAsUser(packageName, 0, user); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException(e); + } + if (!context.isDeviceProtectedStorage()) { + context = context.createDeviceProtectedStorageContext(); + } + return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE); + } + + /** + * Get all role names with fallback disabled, which means their "none" are set to true. + * + * @return A list of role names with fallback disabled. + */ + public static List<String> getFallbackDisabledRoles(@NonNull UserHandle user, + @NonNull Context context) { + List<String> fallbackDisabledRoles = new ArrayList<>(); + SharedPreferences sharedPreferences = getSharedPreferences(user, context); + for (String key : sharedPreferences.getAll().keySet()) { + if (key.startsWith(IS_NONE_ROLE_HOLDER_SELECTED_KEY) + && sharedPreferences.getBoolean(key, false)) { + String roleName = key.substring(IS_NONE_ROLE_HOLDER_SELECTED_KEY.length()); + fallbackDisabledRoles.add(roleName); + } + } + return fallbackDisabledRoles; + } + + /** + * Check whether the role has the fallback holder enabled. + * + * @return whether the "none" role holder is not selected + */ + public static boolean isRoleFallbackEnabledAsUser(@NonNull String roleName, + @NonNull UserHandle user, @NonNull Context context) { + return !getSharedPreferences(user, context) + .getBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + roleName, false); + } + + /** + * Set whether the role has fallback holder enabled. + */ + public static void setRoleFallbackEnabledAsUser(@NonNull String roleName, + boolean fallbackEnabled, @NonNull UserHandle user, @NonNull Context context) { + String key = IS_NONE_ROLE_HOLDER_SELECTED_KEY + roleName; + if (fallbackEnabled) { + getSharedPreferences(user, context).edit().remove(key).apply(); + } else { + getSharedPreferences(user, context).edit().putBoolean(key, true).apply(); + } + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java index 3b11d7d92..365c3b491 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/NotificationUtils.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.Log; @@ -44,41 +45,45 @@ public final class NotificationUtils { /** * Grants the NotificationListener access. * - * @param context the {@code Context} to retrieve system services * @param packageName the package name implements the NotificationListener + * @param user the user of the component + * @param context the {@code Context} to retrieve system services */ - public static void grantNotificationAccessForPackage(@NonNull Context context, - @NonNull String packageName) { - setNotificationGrantStateForPackage(context, packageName, true); + public static void grantNotificationAccessForPackageAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + setNotificationGrantStateForPackageAsUser(packageName, true, user, context); } /** * Revokes the NotificationListener access. * - * @param context the {@code Context} to retrieve system services * @param packageName the package name implements the NotificationListener + * @param user the user of the component + * @param context the {@code Context} to retrieve system services */ - public static void revokeNotificationAccessForPackage(@NonNull Context context, - @NonNull String packageName) { - setNotificationGrantStateForPackage(context, packageName, false); + public static void revokeNotificationAccessForPackageAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + setNotificationGrantStateForPackageAsUser(packageName, false, user, context); } - private static void setNotificationGrantStateForPackage(@NonNull Context context, - @NonNull String packageName, boolean granted) { + private static void setNotificationGrantStateForPackageAsUser(@NonNull String packageName, + boolean granted, @NonNull UserHandle user, @NonNull Context context) { List<ComponentName> notificationListenersForPackage = - getNotificationListenersForPackage(packageName, context); - NotificationManager notificationManager = - context.getSystemService(NotificationManager.class); + getNotificationListenersForPackageAsUser(packageName, user, context); + Context userContext = UserUtils.getUserContext(context, user); + NotificationManager userNotificationManager = + userContext.getSystemService(NotificationManager.class); for (ComponentName componentName : notificationListenersForPackage) { - notificationManager.setNotificationListenerAccessGranted( + userNotificationManager.setNotificationListenerAccessGranted( componentName, granted, false); } } - private static List<ComponentName> getNotificationListenersForPackage( - @NonNull String packageName, @NonNull Context context) { - List<ResolveInfo> allListeners = context.getPackageManager().queryIntentServices( + private static List<ComponentName> getNotificationListenersForPackageAsUser( + @NonNull String packageName, @NonNull UserHandle user, @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + List<ResolveInfo> allListeners = userContext.getPackageManager().queryIntentServices( new Intent(NotificationListenerService.SERVICE_INTERFACE).setPackage(packageName), PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); ArrayList<ComponentName> pkgListeners = new ArrayList<>(); diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java index 4b127ad10..cbffd451a 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/PackageUtils.java @@ -36,19 +36,21 @@ public final class PackageUtils { * Retrieve the {@link PackageInfo} of an application. * * @param packageName the package name of the application - * @param extraFlags the extra flags to pass to {@link PackageManager#getPackageInfo(String, - * int)} - * @param context the {@code Context} to retrieve system services - * + * @param extraFlags the extra flags to pass to {@link PackageManager#getPackageInfo(String, + * int)} + * @param user the user of the application + * @param context the {@code Context} to retrieve system services * @return the {@link PackageInfo} of the application, or {@code null} if not found */ @Nullable - public static PackageInfo getPackageInfo(@NonNull String packageName, int extraFlags, - @NonNull Context context) { - PackageManager packageManager = context.getPackageManager(); + public static PackageInfo getPackageInfoAsUser(@NonNull String packageName, int extraFlags, + @NonNull UserHandle user, @NonNull Context context) { + Context userContext = UserUtils.getUserContext(context, user); + PackageManager userPackageManager = userContext.getPackageManager(); try { - return packageManager.getPackageInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | extraFlags); + return userPackageManager.getPackageInfo(packageName, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | extraFlags); } catch (PackageManager.NameNotFoundException e) { return null; } @@ -58,12 +60,15 @@ public final class PackageUtils { * Retrieve if a package is a system package. * * @param packageName the name of the package + * @param user the user of the package * @param context the {@code Context} to retrieve system services * * @return whether the package is a system package */ - public static boolean isSystemPackage(@NonNull String packageName, @NonNull Context context) { - return getPackageInfo(packageName, PackageManager.MATCH_SYSTEM_ONLY, context) != null; + public static boolean isSystemPackageAsUser(@NonNull String packageName, + @NonNull UserHandle user, @NonNull Context context) { + return getPackageInfoAsUser(packageName, PackageManager.MATCH_SYSTEM_ONLY, user, context) + != null; } /** diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java new file mode 100644 index 000000000..f8f12108a --- /dev/null +++ b/PermissionController/role-controller/java/com/android/role/controller/util/ResourceUtils.java @@ -0,0 +1,57 @@ +/* + * 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.role.controller.util; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.permission.flags.Flags; + +import androidx.annotation.NonNull; + +import com.android.modules.utils.build.SdkLevel; + +public class ResourceUtils { + + private ResourceUtils() {} + + public static String RESOURCE_PACKAGE_NAME_PERMISSION_CONTROLLER = + "com.android.permissioncontroller"; + + /** + * Get a {@link Resources} object to be used to access PermissionController resources. + */ + @NonNull + public static Resources getPermissionControllerResources(@NonNull Context context) { + return getPermissionControllerContext(context).getResources(); + } + + @NonNull + private static Context getPermissionControllerContext(@NonNull Context context) { + if (!SdkLevel.isAtLeastV() || !Flags.systemServerRoleControllerEnabled()) { + // We don't have the getPermissionControllerPackageName() API below V, + // but role controller always runs in PermissionController below V. + return context; + } + String packageName = context.getPackageManager().getPermissionControllerPackageName(); + try { + return context.createPackageContext(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException("Cannot create PermissionController context", e); + } + } +} diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java index 8a6fd579c..ec63528d1 100644 --- a/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java +++ b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java @@ -18,8 +18,8 @@ package com.android.role.controller.util; import android.app.role.RoleManager; import android.content.Context; -import android.content.SharedPreferences; import android.os.UserHandle; +import android.permission.flags.Flags; import androidx.annotation.NonNull; @@ -31,16 +31,7 @@ import com.android.role.controller.model.Role; */ public class RoleManagerCompat { - /** - * Key in the generic shared preferences that stores if the user manually selected the "none" - * role holder for a role. - */ - private static final String IS_NONE_ROLE_HOLDER_SELECTED_KEY = "is_none_role_holder_selected:"; - /** - * Name of generic shared preferences file. - */ - private static final String PREFERENCES_FILE = "preferences"; private RoleManagerCompat() {} @@ -56,47 +47,34 @@ public class RoleManagerCompat { } /** - * Get a device protected storage based shared preferences. Avoid storing sensitive data in it. - * - * @param context the context to get the shared preferences - * @return a device protected storage based shared preferences - */ - @NonNull - private static SharedPreferences getDeviceProtectedSharedPreferences(@NonNull Context context) { - if (!context.isDeviceProtectedStorage()) { - context = context.createDeviceProtectedStorageContext(); - } - return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE); - } - - /** * Check whether the role has the fallback holder enabled. * * @return whether the "none" role holder is not selected */ public static boolean isRoleFallbackEnabledAsUser(@NonNull Role role, @NonNull UserHandle user, @NonNull Context context) { - Context userContext = UserUtils.getUserContext(context, user); - boolean isNoneHolderSelected = getDeviceProtectedSharedPreferences(userContext) - .getBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), false); - return !isNoneHolderSelected; + if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) { + Context userContext = UserUtils.getUserContext(context, user); + RoleManager userRoleManager = userContext.getSystemService(RoleManager.class); + return userRoleManager.isRoleFallbackEnabled(role.getName()); + } else { + return LegacyRoleFallbackEnabledUtils.isRoleFallbackEnabledAsUser(role.getName(), user, + context); + } } /** * Set whether the role has fallback holder enabled. - * */ public static void setRoleFallbackEnabledAsUser(@NonNull Role role, boolean fallbackEnabled, @NonNull UserHandle user, @NonNull Context context) { - Context userContext = UserUtils.getUserContext(context, user); - if (fallbackEnabled) { - getDeviceProtectedSharedPreferences(userContext).edit() - .remove(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName()) - .apply(); + if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) { + Context userContext = UserUtils.getUserContext(context, user); + RoleManager userRoleManager = userContext.getSystemService(RoleManager.class); + userRoleManager.setRoleFallbackEnabled(role.getName(), fallbackEnabled); } else { - getDeviceProtectedSharedPreferences(userContext).edit() - .putBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), true) - .apply(); + LegacyRoleFallbackEnabledUtils.setRoleFallbackEnabledAsUser(role.getName(), + fallbackEnabled, user, context); } } } |