summaryrefslogtreecommitdiff
path: root/framework-s/java
diff options
context:
space:
mode:
author Xin Li <delphij@google.com> 2025-03-08 16:10:00 -0800
committer Xin Li <delphij@google.com> 2025-03-08 16:10:00 -0800
commit2f62693aee03f7c1c6c7c6518e96f33062ba9583 (patch)
tree8b926ecdad1b8692df679665f5d239252b6dbd77 /framework-s/java
parent40f9ebe87a821bdafdeabf9964f54309259483a4 (diff)
parent31dcc618ad79bff7c733867614496c7de7059168 (diff)
Merge 25Q1 (ab/BP1A.250305.020) to AOSP main
Bug: 385190204 Merged-In: I47038580b42eebc4d420ba35d2bb6bedc6d660e3 Change-Id: Ic922b8088ee6990eaa48309755befafe4ceab036
Diffstat (limited to 'framework-s/java')
-rw-r--r--framework-s/java/android/app/ecm/EnhancedConfirmationManager.java11
-rw-r--r--framework-s/java/android/app/role/IRoleManager.aidl12
-rw-r--r--framework-s/java/android/app/role/RoleManager.java204
-rw-r--r--framework-s/java/android/permission/internal/compat/UserHandleCompat.java66
-rw-r--r--framework-s/java/android/permission/internal/compat/package-info.java22
5 files changed, 312 insertions, 3 deletions
diff --git a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
index 74062165e..db05a0af6 100644
--- a/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
+++ b/framework-s/java/android/app/ecm/EnhancedConfirmationManager.java
@@ -20,6 +20,7 @@ import static android.annotation.SdkConstant.SdkConstantType.BROADCAST_INTENT_AC
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
@@ -35,15 +36,13 @@ import android.os.RemoteException;
import android.permission.flags.Flags;
import android.util.ArraySet;
-import androidx.annotation.NonNull;
-
import java.lang.annotation.Retention;
/**
* This class provides the core API for ECM (Enhanced Confirmation Mode). ECM is a feature that
* restricts access to protected **settings** (i.e., sensitive resources) by restricted **apps**
* (apps from from dangerous sources, such as sideloaded packages or packages downloaded from a web
- * browser).
+ * browser), or restricts settings globally based on device state.
*
* <p>Specifically, this class provides the ability to:
*
@@ -71,6 +70,9 @@ import java.lang.annotation.Retention;
* particular app restricted is an implementation detail of ECM. However, the user is able to
* clear any restricted app's restriction status (i.e, un-restrict it), after which ECM will
* consider the app **not restricted**.
+ * <li>A setting may be globally restricted based on device state. In this case, any app may be
+ * automatically considered *restricted*, regardless of the app's restriction state. Users
+ * cannot un-restrict the app, in these cases.
* </ol>
*
* Why is ECM needed? Consider the following (pre-ECM) scenario:
@@ -313,6 +315,9 @@ public final class EnhancedConfirmationManager {
* <p>This should be called from the "Restricted setting" dialog (which {@link
* #createRestrictedSettingDialogIntent} directs to) upon being presented to the user.
*
+ * <p>This restriction clearing does not apply to any settings that are restricted based on
+ * global device state
+ *
* @param packageName package name of the application which should be considered acknowledged
* @throws NameNotFoundException if the provided package was not found
*/
diff --git a/framework-s/java/android/app/role/IRoleManager.aidl b/framework-s/java/android/app/role/IRoleManager.aidl
index 522967630..dc5bc8cb4 100644
--- a/framework-s/java/android/app/role/IRoleManager.aidl
+++ b/framework-s/java/android/app/role/IRoleManager.aidl
@@ -45,6 +45,10 @@ interface IRoleManager {
void setDefaultApplicationAsUser(in String roleName, in String packageName, int flags,
int userId, in RemoteCallback callback);
+ int getActiveUserForRoleAsUser(in String roleName, int userId);
+
+ void setActiveUserForRoleAsUser(in String roleName, int activeUserId, int flags, int userId);
+
void addOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener, int userId);
void removeOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener,
@@ -80,4 +84,12 @@ interface IRoleManager {
boolean isApplicationVisibleForRoleAsUser(in String roleName, in String packageName,
int userId);
+
+ List<String> getDefaultHoldersForTest(in String roleName);
+
+ void setDefaultHoldersForTest(in String roleName, in List<String> packageNames);
+
+ boolean isRoleVisibleForTest(in String roleName);
+
+ void setRoleVisibleForTest(in String roleName, boolean visible);
}
diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java
index 4b8c9b388..42445b4d6 100644
--- a/framework-s/java/android/app/role/RoleManager.java
+++ b/framework-s/java/android/app/role/RoleManager.java
@@ -40,6 +40,7 @@ import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.permission.flags.Flags;
+import android.permission.internal.compat.UserHandleCompat;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -211,6 +212,16 @@ public final class RoleManager {
"android.app.role.SYSTEM_CALL_STREAMING";
/**
+ * The name of the role used for testing cross-user roles.
+ *
+ * @hide
+ */
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ @SystemApi
+ public static final String ROLE_RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY =
+ "android.app.role.RESERVED_FOR_TESTING_PROFILE_GROUP_EXCLUSIVITY";
+
+ /**
* @hide
*/
@IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
@@ -574,6 +585,87 @@ public final class RoleManager {
}
}
+ /**
+ * Get the {@link UserHandle} of the user who that is the active user for the specified role.
+ * <p>
+ * Only profile-group exclusive roles can be used with this method, and they will
+ * have one active user within a profile group.
+ * <p>
+ * <strong>Note:</strong> Using this API requires holding
+ * {@code android.permission.INTERACT_ACROSS_USERS_FULL} and one of
+ * {@code android.permission.MANAGE_ROLE_HOLDERS} or
+ * {@code android.permission.MANAGE_DEFAULT_APPLICATIONS}.
+ *
+ * @param roleName the name of the role to get the active user for
+ *
+ * @return a {@link UserHandle} of the active user for the specified role
+ *
+ * @see #setActiveUserForRole(String, UserHandle, int)
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.MANAGE_ROLE_HOLDERS,
+ Manifest.permission.MANAGE_DEFAULT_APPLICATIONS},
+ conditional = true)
+ @RequiresApi(Build.VERSION_CODES.BAKLAVA)
+ @SystemApi
+ @UserHandleAware
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ @Nullable
+ public UserHandle getActiveUserForRole(@NonNull String roleName) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ try {
+ int userId = mService.getActiveUserForRoleAsUser(roleName,
+ mContext.getUser().getIdentifier());
+ return userId == UserHandleCompat.USER_NULL ? null : UserHandle.of(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set a specific user as active user for a role.
+ * <p>
+ * Only profile-group exclusive roles can be used with this method, and they will have
+ * one active user within a profile group.
+ * <p>
+ * <strong>Note:</strong> Using this API requires holding
+ * {@code android.permission.INTERACT_ACROSS_USERS_FULL} and one of
+ * {@code android.permission.MANAGE_ROLE_HOLDERS} or
+ * {@code android.permission.MANAGE_DEFAULT_APPLICATIONS}.
+ *
+ * @param roleName the name of the role to set the active user for
+ * @param user the user to set as active user for specified role
+ * @param flags optional behavior flags
+ *
+ * @see #getActiveUserForRole(String)
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.MANAGE_ROLE_HOLDERS,
+ Manifest.permission.MANAGE_DEFAULT_APPLICATIONS},
+ conditional = true)
+ @RequiresApi(Build.VERSION_CODES.BAKLAVA)
+ @SystemApi
+ @UserHandleAware
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ // The user handle parameter is a value to be set by this method, while the context user of the
+ // operation is indeed read from the context
+ @SuppressLint("UserHandle")
+ public void setActiveUserForRole(
+ @NonNull String roleName, @NonNull UserHandle user, @ManageHoldersFlags int flags) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Objects.requireNonNull(user, "user cannot be null");
+ try {
+ mService.setActiveUserForRoleAsUser(roleName, user.getIdentifier(), flags,
+ mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@NonNull
private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
@NonNull Consumer<Boolean> callback) {
@@ -1074,6 +1166,118 @@ public final class RoleManager {
}
}
+ /**
+ * Get the default holders of this role, which will be added when the role is added for the
+ * first time.
+ * <p>
+ * <strong>Note:</strong> Use of this API should be limited to tests. The values returned are
+ * not persisted.
+ * <p>
+ * Throws {@link IllegalArgumentException} if role is not a test role
+ *
+ * @param roleName the name of the role to get test default holders for
+ * @return the list of package names of the default holders
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @RequiresApi(Build.VERSION_CODES.BAKLAVA)
+ @SystemApi
+ @UserHandleAware
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ @NonNull
+ public List<String> getDefaultHoldersForTest(@NonNull String roleName) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ try {
+ return mService.getDefaultHoldersForTest(roleName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set the default holders of this role, which will be added when the role is added for the
+ * first time.
+ * <p>
+ * <strong>Note:</strong> Use of this API should be limited to tests. The values used are
+ * not persisted.
+ * <p>
+ * Throws {@link IllegalArgumentException} if role is not a test role
+ *
+ * @param roleName the name of the role to set test default holders for
+ * @param packageNames a list of package names of the default holders or {@code null} to unset
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @RequiresApi(Build.VERSION_CODES.BAKLAVA)
+ @SystemApi
+ @UserHandleAware
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ public void setDefaultHoldersForTest(
+ @NonNull String roleName, @Nullable List<String> packageNames) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ try {
+ mService.setDefaultHoldersForTest(roleName, packageNames);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get whether a role should be visible for testing.
+ * <p>
+ * <strong>Note:</strong> Use of this API should be limited to tests. The values returned are
+ * not persisted.
+ * <p>
+ * Throws {@link IllegalArgumentException} if role is not a test role
+ *
+ * @param roleName the name of the role to get test visibility for
+ * @return {@code true} if role is visible, {@code false} otherwise
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @RequiresApi(Build.VERSION_CODES.BAKLAVA)
+ @SystemApi
+ @UserHandleAware
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ public boolean isRoleVisibleForTest(@NonNull String roleName) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ try {
+ return mService.isRoleVisibleForTest(roleName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set whether a role should be visible for testing.
+ * <p>
+ * <strong>Note:</strong> Use of this API should be limited to tests. The values used are
+ * not persisted.
+ * <p>
+ * Throws {@link IllegalArgumentException} if role is not a test role
+ *
+ * @param roleName the name of the role to set test visibility for
+ * @param visible {@code true} to set role as visible, {@code false} otherwise
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @RequiresApi(Build.VERSION_CODES.BAKLAVA)
+ @SystemApi
+ @UserHandleAware
+ @FlaggedApi(com.android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_ENABLED)
+ public void setRoleVisibleForTest(@NonNull String roleName, boolean visible) {
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ try {
+ mService.setRoleVisibleForTest(roleName, visible);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@NonNull
private RoleControllerManager getRoleControllerManager() {
synchronized (mRoleControllerManagerLock) {
diff --git a/framework-s/java/android/permission/internal/compat/UserHandleCompat.java b/framework-s/java/android/permission/internal/compat/UserHandleCompat.java
new file mode 100644
index 000000000..8a3ec444d
--- /dev/null
+++ b/framework-s/java/android/permission/internal/compat/UserHandleCompat.java
@@ -0,0 +1,66 @@
+/*
+ * 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 android.permission.internal.compat;
+
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+
+/**
+ * Helper for accessing features in {@link UserHandle}.
+ */
+public final class UserHandleCompat {
+ /**
+ * A user ID to indicate all users on the device.
+ */
+ public static final int USER_ALL = UserHandle.ALL.getIdentifier();
+
+ /**
+ * A user ID to indicate an undefined user of the device.
+ *
+ * @see UserHandle#USER_NULL
+ */
+ public static final @UserIdInt int USER_NULL = -10000;
+
+ /**
+ * A user ID to indicate the "system" user of the device.
+ */
+ public static final int USER_SYSTEM = UserHandle.SYSTEM.getIdentifier();
+
+ private UserHandleCompat() {}
+
+ /**
+ * Get the user ID of a given UID.
+ *
+ * @param uid the UID
+ * @return the user ID
+ */
+ @UserIdInt
+ public static int getUserId(int uid) {
+ return UserHandle.getUserHandleForUid(uid).getIdentifier();
+ }
+
+ /**
+ * Get the UID from the give user ID and app ID
+ *
+ * @param userId the user ID
+ * @param appId the app ID
+ * @return the UID
+ */
+ public static int getUid(@UserIdInt int userId, int appId) {
+ return UserHandle.of(userId).getUid(appId);
+ }
+}
diff --git a/framework-s/java/android/permission/internal/compat/package-info.java b/framework-s/java/android/permission/internal/compat/package-info.java
new file mode 100644
index 000000000..b78aac878
--- /dev/null
+++ b/framework-s/java/android/permission/internal/compat/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * @hide
+ * TODO(b/146466118) remove this javadoc tag
+ */
+@android.annotation.Hide
+package android.permission.internal.compat;