Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b20c5d9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topic "non-emm management" into main

* changes:
  Migrate setPackagesSuspended
  Enable coexistable device policy APIs for non-EMM management
parents 5bbed60e 12e2998c
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -5842,6 +5842,24 @@ public class DevicePolicyManager {
     * with {@link #PASSWORD_QUALITY_UNSPECIFIED} on that instance prior to setting complexity
     * requirement for the managed profile.
     *
     * Starting from {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, after the password
     * requirement has been set, {@link PolicyUpdateReceiver#onPolicySetResult(Context, String,
     * Bundle, TargetUser, PolicyUpdateResult)} will notify the admin on whether the policy was
     * successfully set or not. This callback will contain:
     * <ul>
     * <li> The policy identifier {@link DevicePolicyIdentifiers#PASSWORD_COMPLEXITY_POLICY}
     * <li> The {@link TargetUser} that this policy relates to
     * <li> The {@link PolicyUpdateResult}, which will be
     * {@link PolicyUpdateResult#RESULT_POLICY_SET} if the policy was successfully set or the
     * reason the policy failed to be set
     * e.g. {@link PolicyUpdateResult#RESULT_FAILURE_CONFLICTING_ADMIN_POLICY})
     * </ul>
     * If there has been a change to the policy,
     * {@link PolicyUpdateReceiver#onPolicyChanged(Context, String, Bundle, TargetUser,
     * PolicyUpdateResult)} will notify the admin of this change. This callback will contain the
     * same parameters as PolicyUpdateReceiver#onPolicySetResult and the {@link PolicyUpdateResult}
     * will contain the reason why the policy changed.
     *
     * @throws SecurityException if the calling application is not a device owner or a profile
     * owner.
     * @throws IllegalArgumentException if the complexity level is not one of the four above.
@@ -5849,6 +5867,7 @@ public class DevicePolicyManager {
     * are password requirements specified using {@link #setPasswordQuality(ComponentName, int)}
     * on the parent {@code DevicePolicyManager} instance.
     */
    @SupportsCoexistence
    @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional = true)
    public void setRequiredPasswordComplexity(@PasswordComplexity int passwordComplexity) {
        if (mService == null) {
@@ -5880,6 +5899,7 @@ public class DevicePolicyManager {
     * owner.
     */
    @PasswordComplexity
    @SupportsCoexistence
    @RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS, conditional = true)
    public int getRequiredPasswordComplexity() {
        if (mService == null) {
+10 −0
Original line number Diff line number Diff line
@@ -327,6 +327,16 @@ flag {
  }
}

flag {
    name: "unmanaged_mode_migration"
    namespace: "enterprise"
    description: "Migrate APIs for unmanaged mode"
    bug: "335624297"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "headless_single_user_fixes"
    namespace: "enterprise"
+92 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.devicepolicy;

import static android.app.admin.DevicePolicyIdentifiers.PACKAGES_SUSPENDED_POLICY;
import static android.app.admin.DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY;
import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_TARGET_USER_ID;
import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_UPDATE_RESULT_KEY;
@@ -78,6 +79,10 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -260,9 +265,7 @@ final class DevicePolicyEngine {
                boolean policyEnforced = Objects.equals(
                        localPolicyState.getCurrentResolvedPolicy(), value);
                // TODO(b/285532044): remove hack and handle properly
                if (!policyEnforced
                        && policyDefinition.getPolicyKey().getIdentifier().equals(
                        USER_CONTROL_DISABLED_PACKAGES_POLICY)) {
                if (!policyEnforced && shouldApplyPackageSetUnionPolicyHack(policyDefinition)) {
                    PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value;
                    PolicyValue<Set<String>> parsedResolvedValue =
                            (PolicyValue<Set<String>>) localPolicyState.getCurrentResolvedPolicy();
@@ -528,8 +531,7 @@ final class DevicePolicyEngine {
                        globalPolicyState.getCurrentResolvedPolicy(), value);
                // TODO(b/285532044): remove hack and handle properly
                if (!policyAppliedGlobally
                        && policyDefinition.getPolicyKey().getIdentifier().equals(
                        USER_CONTROL_DISABLED_PACKAGES_POLICY)) {
                        && shouldApplyPackageSetUnionPolicyHack(policyDefinition)) {
                    PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value;
                    PolicyValue<Set<String>> parsedResolvedValue =
                            (PolicyValue<Set<String>>) globalPolicyState.getCurrentResolvedPolicy();
@@ -666,8 +668,7 @@ final class DevicePolicyEngine {

            }
            // TODO(b/285532044): remove hack and handle properly
            if (policyDefinition.getPolicyKey().getIdentifier().equals(
                    USER_CONTROL_DISABLED_PACKAGES_POLICY)) {
            if (shouldApplyPackageSetUnionPolicyHack(policyDefinition)) {
                if (!Objects.equals(value, localPolicyState.getCurrentResolvedPolicy())) {
                    PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value;
                    PolicyValue<Set<String>> parsedResolvedValue =
@@ -688,6 +689,12 @@ final class DevicePolicyEngine {
     */
    @Nullable
    <V> V getResolvedPolicy(@NonNull PolicyDefinition<V> policyDefinition, int userId) {
        PolicyValue<V> resolvedValue = getResolvedPolicyValue(policyDefinition, userId);
        return resolvedValue == null ? null : resolvedValue.getValue();
    }

    private <V> PolicyValue<V> getResolvedPolicyValue(@NonNull PolicyDefinition<V> policyDefinition,
            int userId) {
        Objects.requireNonNull(policyDefinition);

        synchronized (mLock) {
@@ -699,9 +706,37 @@ final class DevicePolicyEngine {
                resolvedValue = getGlobalPolicyStateLocked(
                        policyDefinition).getCurrentResolvedPolicy();
            }
            return resolvedValue == null ? null : resolvedValue.getValue();
            return resolvedValue;
        }
    }

    /**
     * Retrieves resolved policy for the provided {@code policyDefinition} and a list of
     * users.
     */
    @Nullable
    <V> V getResolvedPolicyAcrossUsers(@NonNull PolicyDefinition<V> policyDefinition,
            List<Integer> users) {
        Objects.requireNonNull(policyDefinition);

        List<PolicyValue<V>> adminPolicies = new ArrayList<>();
        synchronized (mLock) {
            for (int userId : users) {
                PolicyValue<V> resolvedValue = getResolvedPolicyValue(policyDefinition, userId);
                if (resolvedValue != null) {
                    adminPolicies.add(resolvedValue);
                }
            }
        }
        // We will be aggregating PolicyValue across multiple admins across multiple users,
        // including different policies set by the same admin on different users. This is
        // not supported by ResolutionMechanism generically, instead we need to call the special
        // resolve() method that doesn't care about admins who set the policy. Note that not every
        // ResolutionMechanism supports this.
        PolicyValue<V> resolvedValue =
                policyDefinition.getResolutionMechanism().resolve(adminPolicies);
        return resolvedValue == null ? null : resolvedValue.getValue();
    }

    /**
     * Retrieves the policy set by the admin for the provided {@code policyDefinition} and
@@ -1743,6 +1778,18 @@ final class DevicePolicyEngine {
        }
    }

    /**
     * Create a backup of the policy engine XML file, so that we can recover previous state
     * in case some data-loss bug is triggered e.g. during migration.
     *
     * Backup is only created if one with the same ID does not exist yet.
     */
    void createBackup(String backupId) {
        synchronized (mLock) {
            DevicePoliciesReaderWriter.createBackup(backupId);
        }
    }

    <V> void reapplyAllPoliciesOnBootLocked() {
        for (PolicyKey policy : mGlobalPolicies.keySet()) {
            PolicyState<?> policyState = mGlobalPolicies.get(policy);
@@ -1820,8 +1867,22 @@ final class DevicePolicyEngine {
        return false;
    }

    /**
     * For PackageSetUnion policies, we can't simply compare the resolved policy against the admin's
     * policy for equality to determine if the admin has applied the policy successfully, instead
     * the admin's policy should be considered applied successfully as long as its policy is subset
     * of the resolved policy. This method controls which policies should use this special logic.
     */
    private <V> boolean shouldApplyPackageSetUnionPolicyHack(PolicyDefinition<V> policy) {
        String policyKey =  policy.getPolicyKey().getIdentifier();
        return policyKey.equals(USER_CONTROL_DISABLED_PACKAGES_POLICY)
                || policyKey.equals(PACKAGES_SUSPENDED_POLICY);
    }

    private class DevicePoliciesReaderWriter {
        private static final String DEVICE_POLICIES_XML = "device_policy_state.xml";
        private static final String BACKUP_DIRECTORY = "device_policy_backups";
        private static final String BACKUP_FILENAME = "device_policy_state.%s.xml";
        private static final String TAG_LOCAL_POLICY_ENTRY = "local-policy-entry";
        private static final String TAG_GLOBAL_POLICY_ENTRY = "global-policy-entry";
        private static final String TAG_POLICY_STATE_ENTRY = "policy-state-entry";
@@ -1836,8 +1897,30 @@ final class DevicePolicyEngine {

        private final File mFile;

        private static File getFileName() {
            return new File(Environment.getDataSystemDirectory(), DEVICE_POLICIES_XML);
        }
        private DevicePoliciesReaderWriter() {
            mFile = new File(Environment.getDataSystemDirectory(), DEVICE_POLICIES_XML);
            mFile = getFileName();
        }

        public static void createBackup(String backupId) {
            try {
                File backupDirectory = new File(Environment.getDataSystemDirectory(),
                        BACKUP_DIRECTORY);
                backupDirectory.mkdir();
                Path backupPath = Path.of(backupDirectory.getPath(),
                        BACKUP_FILENAME.formatted(backupId));
                if (backupPath.toFile().exists()) {
                    Log.w(TAG, "Backup already exist: " + backupPath);
                } else {
                    Files.copy(getFileName().toPath(), backupPath,
                            StandardCopyOption.REPLACE_EXISTING);
                    Log.i(TAG, "Backup created at " + backupPath);
                }
            } catch (Exception e) {
                Log.e(TAG, "Cannot create backup " + backupId, e);
            }
        }

        void writeToFileLocked() {
+413 −60

File changed.

Preview size limit exceeded, changes collapsed.

+8 −5
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.app.admin.PolicyValue;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

final class MostRestrictive<V> extends ResolutionMechanism<V> {

@@ -33,18 +33,21 @@ final class MostRestrictive<V> extends ResolutionMechanism<V> {

    @Override
    PolicyValue<V> resolve(@NonNull LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminPolicies) {
        return resolve(new ArrayList<>(adminPolicies.values()));
    }

    @Override
    PolicyValue<V> resolve(List<PolicyValue<V>> adminPolicies) {
        if (adminPolicies.isEmpty()) {
            return null;
        }
        for (PolicyValue<V> value : mMostToLeastRestrictive) {
            if (adminPolicies.containsValue(value)) {
            if (adminPolicies.contains(value)) {
                return value;
            }
        }
        // Return first set policy if none can be found in known values
        Map.Entry<EnforcingAdmin, PolicyValue<V>> policy =
                adminPolicies.entrySet().stream().findFirst().get();
        return policy.getValue();
        return adminPolicies.get(0);
    }

    @Override
Loading