summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vitor Carvalho <vtrmc@google.com> 2025-01-14 11:41:01 +0000
committer Vitor Carvalho <vtrmc@google.com> 2025-02-13 11:25:49 +0000
commit183aee9bf4937e36f63cbcd4e9a4308479bdbf39 (patch)
tree377e91532775b9b203a0b9ea91684c5fb1693251
parent74b083adfbcaa7d5c8d2df6512e8cad550b65707 (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.txt9
-rw-r--r--core/api/test-current.txt8
-rw-r--r--core/java/android/app/supervision/SupervisionManager.java38
-rw-r--r--core/java/android/app/supervision/flags.aconfig8
-rw-r--r--core/java/android/content/Context.java4
-rw-r--r--services/supervision/java/com/android/server/supervision/SupervisionService.java21
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);