diff options
3 files changed, 122 insertions, 42 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 02de1cd9a137..ae4dcfaf13e2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8049,6 +8049,7 @@ package android.app.admin {      field public static final String ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED = "android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED";      field public static final String ACTION_CHECK_POLICY_COMPLIANCE = "android.app.action.CHECK_POLICY_COMPLIANCE";      field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE"; +    field public static final String ACTION_DEVICE_FINANCING_STATE_CHANGED = "android.app.admin.action.DEVICE_FINANCING_STATE_CHANGED";      field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";      field public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED = "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";      field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE"; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 024141777604..6bbbfe1ef4b0 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -57,6 +57,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa  import android.Manifest.permission;  import android.accounts.Account; +import android.annotation.BroadcastBehavior;  import android.annotation.CallbackExecutor;  import android.annotation.ColorInt;  import android.annotation.IntDef; @@ -3998,6 +3999,27 @@ public class DevicePolicyManager {      public static final String EXTRA_RESOURCE_IDS =              "android.app.extra.RESOURCE_IDS"; +    /** +     * Broadcast Action: Broadcast sent to indicate that the device financing state has changed. +     * +     * <p>This occurs when, for example, a financing kiosk app has been added or removed. +     * +     * <p>To query the current device financing state see {@link #isDeviceFinanced}. +     * +     * <p>This will be delivered to the following apps if they include a receiver for this action +     * in their manifest: +     * <ul> +     *     <li>Device owner admins. +     *     <li>Organization-owned profile owner admins +     *     <li>The supervision app +     *     <li>The device management role holder +     * </ul> +     */ +    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) +    @BroadcastBehavior(explicitOnly = true, includeBackground = true) +    public static final String ACTION_DEVICE_FINANCING_STATE_CHANGED = +            "android.app.admin.action.DEVICE_FINANCING_STATE_CHANGED"; +      /** Allow the user to choose whether to enable MTE on the device. */      public static final int MTE_NOT_CONTROLLED_BY_POLICY = 0; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index a1789b2b125d..720533f6a389 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -95,6 +95,7 @@ import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDG  import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;  import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;  import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; +import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_FINANCING_STATE_CHANGED;  import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;  import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;  import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; @@ -15440,7 +15441,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {              Slogf.i(LOG_TAG, "Sending %s broadcast to manifest receivers.", intent.getAction());              broadcastIntentToCrossProfileManifestReceivers(                      intent, parentHandle, requiresPermission); -            broadcastIntentToDevicePolicyManagerRoleHolder(intent, parentHandle); +            broadcastExplicitIntentToRoleHolder( +                    intent, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, parentHandle);          }          @Override @@ -15481,36 +15483,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {              }          } -        private void broadcastIntentToDevicePolicyManagerRoleHolder( -                Intent intent, UserHandle userHandle) { -            final int userId = userHandle.getIdentifier(); -            final String packageName = getDevicePolicyManagementRoleHolderPackageName(mContext); -            if (packageName == null) { -                return; -            } -            try { -                final Intent packageIntent = new Intent(intent) -                        .setPackage(packageName); -                final List<ResolveInfo> receivers = mIPackageManager.queryIntentReceivers( -                        packageIntent, -                        /* resolvedType= */ null, -                        STOCK_PM_FLAGS, -                        userId).getList(); -                if (receivers.isEmpty()) { -                    return; -                } -                for (ResolveInfo receiver : receivers) { -                    final Intent componentIntent = new Intent(packageIntent) -                            .setComponent(receiver.getComponentInfo().getComponentName()) -                            .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); -                    mContext.sendBroadcastAsUser(componentIntent, userHandle); -                } -            } catch (RemoteException ex) { -                Slogf.w(LOG_TAG, "Cannot get list of broadcast receivers for %s because: %s.", -                        intent.getAction(), ex); -            } -        } -          /**           * Checks whether the package {@code packageName} has the {@code MODIFY_QUIET_MODE}           * permission granted for the user {@code userId}. @@ -20718,7 +20690,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {      private void maybeInstallDevicePolicyManagementRoleHolderInUser(int targetUserId) {          String devicePolicyManagerRoleHolderPackageName = -                getDevicePolicyManagementRoleHolderPackageName(mContext); +                getRoleHolderPackageName(mContext, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);          if (devicePolicyManagerRoleHolderPackageName == null) {              Slogf.d(LOG_TAG, "No device policy management role holder specified.");              return; @@ -20744,14 +20716,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {          }      } +    /** +     * If multiple packages hold the role, returns the first package in the list. +     */ +    @Nullable +    private String getRoleHolderPackageName(Context context, String role) { +        return getRoleHolderPackageNameOnUser(context, role, Process.myUserHandle()); +    } -    private String getDevicePolicyManagementRoleHolderPackageName(Context context) { +    /** +     * If multiple packages hold the role, returns the first package in the list. +     */ +    @Nullable +    private String getRoleHolderPackageNameOnUser(Context context, String role, UserHandle user) {          RoleManager roleManager = context.getSystemService(RoleManager.class);          // Calling identity needs to be cleared as this method is used in the permissions checks.          return mInjector.binderWithCleanCallingIdentity(() -> { -            List<String> roleHolders = -                    roleManager.getRoleHolders(RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT); +            List<String> roleHolders = roleManager.getRoleHoldersAsUser(role, user);              if (roleHolders.isEmpty()) {                  return null;              } @@ -20762,7 +20744,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {      private boolean isCallerDevicePolicyManagementRoleHolder(CallerIdentity caller) {          int callerUid = caller.getUid();          String devicePolicyManagementRoleHolderPackageName = -                getDevicePolicyManagementRoleHolderPackageName(mContext); +                getRoleHolderPackageName(mContext, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT);          int roleHolderUid = mInjector.getPackageManagerInternal().getPackageUid(                  devicePolicyManagementRoleHolderPackageName, 0, caller.getUserId()); @@ -21830,15 +21812,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {          }          public void register() { -            mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.SYSTEM); +            mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);          }          @Override          public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { -            if (!RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT.equals(roleName)) { +            if (RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT.equals(roleName)) { +                handleDevicePolicyManagementRoleChange(user); +                return; +            } +            if (RoleManager.ROLE_FINANCED_DEVICE_KIOSK.equals(roleName)) { +                handleFinancedDeviceKioskRoleChange();                  return;              } -            String newRoleHolder = getRoleHolder(); +        } + +        private void handleDevicePolicyManagementRoleChange(UserHandle user) { +            String newRoleHolder = getDeviceManagementRoleHolder(user);              if (isDefaultRoleHolder(newRoleHolder)) {                  Slogf.i(LOG_TAG,                          "onRoleHoldersChanged: Default role holder is set, returning early"); @@ -21873,9 +21863,42 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {              }          } -        private String getRoleHolder() { -            return DevicePolicyManagerService.this.getDevicePolicyManagementRoleHolderPackageName( -                    mContext); +        private void handleFinancedDeviceKioskRoleChange() { +            if (!isDevicePolicyEngineEnabled()) { +                return; +            } +            Slog.i(LOG_TAG, "Handling action " + ACTION_DEVICE_FINANCING_STATE_CHANGED); +            Intent intent = new Intent(ACTION_DEVICE_FINANCING_STATE_CHANGED); +            mInjector.binderWithCleanCallingIdentity(() -> { +                for (UserInfo userInfo : mUserManager.getUsers()) { +                    UserHandle user = userInfo.getUserHandle(); +                    broadcastExplicitIntentToRoleHolder( +                            intent, RoleManager.ROLE_SYSTEM_SUPERVISION, user); +                    broadcastExplicitIntentToRoleHolder( +                            intent, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, user); +                    ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(user.getIdentifier()); +                    if (admin == null) { +                        continue; +                    } +                    if (!isProfileOwnerOfOrganizationOwnedDevice( +                            admin.info.getComponent(), user.getIdentifier()) +                            && !isDeviceOwner(admin)) { +                        continue; +                    } +                    // Don't send the broadcast twice if the DPC is the same package as the +                    // DMRH +                    if (admin.info.getPackageName().equals(getDeviceManagementRoleHolder(user))) { +                        continue; +                    } +                    broadcastExplicitIntentToPackage( +                            intent, admin.info.getPackageName(), admin.getUserHandle()); +                } +            }); +        } + +        private String getDeviceManagementRoleHolder(UserHandle user) { +            return DevicePolicyManagerService.this.getRoleHolderPackageNameOnUser( +                    mContext, RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT, user);          }          private boolean isDefaultRoleHolder(String packageName) { @@ -21935,6 +21958,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {          }      } +    private void broadcastExplicitIntentToRoleHolder( +            Intent intent, String role, UserHandle userHandle) { +        String packageName = getRoleHolderPackageNameOnUser(mContext, role, userHandle); +        if (packageName == null) { +            return; +        } +        broadcastExplicitIntentToPackage(intent, packageName, userHandle); +    } + +    private void broadcastExplicitIntentToPackage( +            Intent intent, String packageName, UserHandle userHandle) { +        int userId = userHandle.getIdentifier(); +        if (packageName == null) { +            return; +        } +        Intent packageIntent = new Intent(intent) +                .setPackage(packageName); +        List<ResolveInfo> receivers = mContext.getPackageManager().queryBroadcastReceiversAsUser( +                packageIntent, +                PackageManager.ResolveInfoFlags.of(PackageManager.GET_RECEIVERS), +                userId); +        if (receivers.isEmpty()) { +            Slog.i(LOG_TAG, "Found no receivers to handle intent " + intent +                    + " in package " + packageName); +            return; +        } +        for (ResolveInfo receiver : receivers) { +            Intent componentIntent = new Intent(packageIntent) +                    .setComponent(receiver.getComponentInfo().getComponentName()) +                    .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); +            mContext.sendBroadcastAsUser(componentIntent, userHandle); +        } +    } +      @Override      public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {          Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(  |