diff options
author | 2025-01-14 11:41:01 +0000 | |
---|---|---|
committer | 2025-02-13 11:25:49 +0000 | |
commit | 183aee9bf4937e36f63cbcd4e9a4308479bdbf39 (patch) | |
tree | 377e91532775b9b203a0b9ea91684c5fb1693251 | |
parent | 74b083adfbcaa7d5c8d2df6512e8cad550b65707 (diff) |
Enable the SupervisionManager#isSupervisionEnabled API behing a new flag.
Flag: android.app.supervision.flags.supervision_manager_apis
Bug: 381428475
Test: n/a
Change-Id: Ib654250fb4f55fa801c9c05658728e7d8ee62a26
API-Coverage-Bug: 361537805
-rw-r--r-- | core/api/system-current.txt | 9 | ||||
-rw-r--r-- | core/api/test-current.txt | 8 | ||||
-rw-r--r-- | core/java/android/app/supervision/SupervisionManager.java | 38 | ||||
-rw-r--r-- | core/java/android/app/supervision/flags.aconfig | 8 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 4 | ||||
-rw-r--r-- | services/supervision/java/com/android/server/supervision/SupervisionService.java | 21 |
6 files changed, 68 insertions, 20 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 76cce7439454..143358897a15 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2934,6 +2934,14 @@ package android.app.smartspace.uitemplatedata { } +package android.app.supervision { + + @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") public class SupervisionManager { + method @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSupervisionEnabled(); + } + +} + package android.app.time { public final class Capabilities { @@ -3797,6 +3805,7 @@ package android.content { field public static final String SHARED_CONNECTIVITY_SERVICE = "shared_connectivity"; field public static final String SMARTSPACE_SERVICE = "smartspace"; field public static final String STATS_MANAGER = "stats"; + field @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") public static final String SUPERVISION_SERVICE = "supervision"; field public static final String SYSTEM_CONFIG_SERVICE = "system_config"; field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network"; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index e8ff546cc61a..d5526a22d7b0 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -850,6 +850,14 @@ package android.app.prediction { } +package android.app.supervision { + + @FlaggedApi("android.app.supervision.flags.supervision_manager_apis") public class SupervisionManager { + method public void setSupervisionEnabled(boolean); + } + +} + package android.app.usage { public class StorageStatsManager { diff --git a/core/java/android/app/supervision/SupervisionManager.java b/core/java/android/app/supervision/SupervisionManager.java index d30705536045..6b7f4162d084 100644 --- a/core/java/android/app/supervision/SupervisionManager.java +++ b/core/java/android/app/supervision/SupervisionManager.java @@ -16,11 +16,19 @@ package android.app.supervision; +import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.MANAGE_USERS; +import static android.Manifest.permission.QUERY_USERS; + +import android.annotation.FlaggedApi; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.annotation.UserHandleAware; import android.annotation.UserIdInt; +import android.app.supervision.flags.Flags; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.RemoteException; @@ -31,6 +39,8 @@ import android.os.RemoteException; * @hide */ @SystemService(Context.SUPERVISION_SERVICE) +@SystemApi +@FlaggedApi(Flags.FLAG_SUPERVISION_MANAGER_APIS) public class SupervisionManager { private final Context mContext; @Nullable private final ISupervisionManager mService; @@ -47,7 +57,8 @@ public class SupervisionManager { * * @hide */ - public static final String ACTION_ENABLE_SUPERVISION = "android.app.action.ENABLE_SUPERVISION"; + public static final String ACTION_ENABLE_SUPERVISION = + "android.app.supervision.action.ENABLE_SUPERVISION"; /** * Activity action: ask the human user to disable supervision for this user. Only the app that @@ -62,7 +73,7 @@ public class SupervisionManager { * @hide */ public static final String ACTION_DISABLE_SUPERVISION = - "android.app.action.DISABLE_SUPERVISION"; + "android.app.supervision.action.DISABLE_SUPERVISION"; /** @hide */ @UnsupportedAppUsage @@ -76,7 +87,10 @@ public class SupervisionManager { * * @hide */ - @UserHandleAware + @SystemApi + @FlaggedApi(Flags.FLAG_SUPERVISION_MANAGER_APIS) + @RequiresPermission(anyOf = {MANAGE_USERS, QUERY_USERS}) + @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS) public boolean isSupervisionEnabled() { return isSupervisionEnabledForUser(mContext.getUserId()); } @@ -84,14 +98,10 @@ public class SupervisionManager { /** * Returns whether the device is supervised. * - * <p>The caller must be from the same user as the target or hold the {@link - * android.Manifest.permission#INTERACT_ACROSS_USERS} permission. - * * @hide */ - @RequiresPermission( - value = android.Manifest.permission.INTERACT_ACROSS_USERS, - conditional = true) + @RequiresPermission(anyOf = {MANAGE_USERS, QUERY_USERS}) + @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS) public boolean isSupervisionEnabledForUser(@UserIdInt int userId) { if (mService != null) { try { @@ -108,7 +118,8 @@ public class SupervisionManager { * * @hide */ - @UserHandleAware + @TestApi + @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS) public void setSupervisionEnabled(boolean enabled) { setSupervisionEnabledForUser(mContext.getUserId(), enabled); } @@ -116,14 +127,9 @@ public class SupervisionManager { /** * Sets whether the device is supervised for a given user. * - * <p>The caller must be from the same user as the target or hold the {@link - * android.Manifest.permission#INTERACT_ACROSS_USERS} permission. - * * @hide */ - @RequiresPermission( - value = android.Manifest.permission.INTERACT_ACROSS_USERS, - conditional = true) + @UserHandleAware(requiresPermissionIfNotCaller = INTERACT_ACROSS_USERS) public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) { if (mService != null) { try { diff --git a/core/java/android/app/supervision/flags.aconfig b/core/java/android/app/supervision/flags.aconfig index 232883cbfe00..94de03877fd7 100644 --- a/core/java/android/app/supervision/flags.aconfig +++ b/core/java/android/app/supervision/flags.aconfig @@ -64,3 +64,11 @@ flag { description: "Flag that enables the Supervision pin recovery screen with Supervision settings entry point" bug: "390500290" } + +flag { + name: "supervision_manager_apis" + is_exported: true + namespace: "supervision" + description: "Flag that enables system APIs in Supervision Manager" + bug: "382034839" +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 8378695fd7a7..96a069f65244 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -17,8 +17,8 @@ package android.content; import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER; -import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS; import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE_MODULE; +import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS; import static android.security.Flags.FLAG_SECURE_LOCKDOWN; import android.annotation.AttrRes; @@ -6858,6 +6858,8 @@ public abstract class Context { * @see android.app.supervision.SupervisionManager * @hide */ + @SystemApi + @FlaggedApi(android.app.supervision.flags.Flags.FLAG_SUPERVISION_MANAGER_APIS) public static final String SUPERVISION_SERVICE = "supervision"; /** diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java index a96c477c78d2..983e63bc325d 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionService.java +++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java @@ -17,6 +17,8 @@ package com.android.server.supervision; import static android.Manifest.permission.INTERACT_ACROSS_USERS; +import static android.Manifest.permission.MANAGE_USERS; +import static android.Manifest.permission.QUERY_USERS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.internal.util.Preconditions.checkCallAuthorization; @@ -86,6 +88,7 @@ public class SupervisionService extends ISupervisionManager.Stub { */ @Override public boolean isSupervisionEnabledForUser(@UserIdInt int userId) { + enforceAnyPermission(QUERY_USERS, MANAGE_USERS); if (UserHandle.getUserId(Binder.getCallingUid()) != userId) { enforcePermission(INTERACT_ACROSS_USERS); } @@ -96,6 +99,7 @@ public class SupervisionService extends ISupervisionManager.Stub { @Override public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) { + // TODO(b/395630828): Ensure that this method can only be called by the system. if (UserHandle.getUserId(Binder.getCallingUid()) != userId) { enforcePermission(INTERACT_ACROSS_USERS); } @@ -181,8 +185,8 @@ public class SupervisionService extends ISupervisionManager.Stub { * Ensures that supervision is enabled when the supervision app is the profile owner. * * <p>The state syncing with the DevicePolicyManager can only enable supervision and never - * disable. Supervision can only be disabled explicitly via calls to the - * {@link #setSupervisionEnabledForUser} method. + * disable. Supervision can only be disabled explicitly via calls to the {@link + * #setSupervisionEnabledForUser} method. */ private void syncStateWithDevicePolicyManager(@UserIdInt int userId) { final DevicePolicyManagerInternal dpmInternal = mInjector.getDpmInternal(); @@ -221,6 +225,17 @@ public class SupervisionService extends ISupervisionManager.Stub { mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED); } + /** Enforces that the caller has at least one of the given permission. */ + private void enforceAnyPermission(String... permissions) { + boolean authorized = false; + for (String permission : permissions) { + if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { + authorized = true; + } + } + checkCallAuthorization(authorized); + } + /** Provides local services in a lazy manner. */ static class Injector { private final Context mContext; @@ -280,7 +295,7 @@ public class SupervisionService extends ISupervisionManager.Stub { } @VisibleForTesting - @SuppressLint("MissingPermission") // not needed for a system service + @SuppressLint("MissingPermission") void registerProfileOwnerListener() { IntentFilter poIntentFilter = new IntentFilter(); poIntentFilter.addAction(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED); |