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

Commit 92d4644c authored by Kholoud Mohamed's avatar Kholoud Mohamed
Browse files

Use DPMS lock for the policy engine

Fixes: 281485588
Test: btest  android.devicepolicy.cts.DeviceManagementCoexistenceTest
Change-Id: Ib09eb833c9f5cc2ee801e3886e3de3f0b0f38c74
parent f4f5ce43
Loading
Loading
Loading
Loading
+119 −106
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ final class DevicePolicyEngine {
    private final UserManager mUserManager;

    // TODO(b/256849338): add more granular locks
    private final Object mLock = new Object();
    private final Object mLock;

    /**
     * Map of <userId, Map<policyKey, policyState>>
@@ -122,9 +122,11 @@ final class DevicePolicyEngine {

    DevicePolicyEngine(
            @NonNull Context context,
            @NonNull DeviceAdminServiceController deviceAdminServiceController) {
            @NonNull DeviceAdminServiceController deviceAdminServiceController,
            @NonNull Object lock) {
        mContext = Objects.requireNonNull(context);
        mDeviceAdminServiceController = Objects.requireNonNull(deviceAdminServiceController);
        mLock = Objects.requireNonNull(lock);
        mUserManager = mContext.getSystemService(UserManager.class);
        mLocalPolicies = new SparseArray<>();
        mGlobalPolicies = new HashMap<>();
@@ -152,8 +154,8 @@ final class DevicePolicyEngine {
            PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);

            if (policyDefinition.isNonCoexistablePolicy()) {
                setNonCoexistableLocalPolicy(policyDefinition, localPolicyState, enforcingAdmin,
                        value, userId, skipEnforcePolicy);
                setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
                        enforcingAdmin, value, userId, skipEnforcePolicy);
                return;
            }

@@ -173,7 +175,7 @@ final class DevicePolicyEngine {
            // the data structures.
            if (!skipEnforcePolicy) {
                if (policyChanged) {
                    onLocalPolicyChanged(policyDefinition, enforcingAdmin, userId);
                    onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
                }
                boolean policyEnforced = Objects.equals(
                        localPolicyState.getCurrentResolvedPolicy(), value);
@@ -211,7 +213,7 @@ final class DevicePolicyEngine {
     *
     * <p>Passing a {@code null} value means the policy set by this admin should be removed.
     */
    private <V> void setNonCoexistableLocalPolicy(
    private <V> void setNonCoexistableLocalPolicyLocked(
            PolicyDefinition<V> policyDefinition,
            PolicyState<V> localPolicyState,
            EnforcingAdmin enforcingAdmin,
@@ -266,8 +268,8 @@ final class DevicePolicyEngine {
            PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);

            if (policyDefinition.isNonCoexistablePolicy()) {
                setNonCoexistableLocalPolicy(policyDefinition, localPolicyState, enforcingAdmin,
                        /* value= */ null, userId, /* skipEnforcePolicy= */ false);
                setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
                        enforcingAdmin, /* value= */ null, userId, /* skipEnforcePolicy= */ false);
                return;
            }

@@ -282,7 +284,7 @@ final class DevicePolicyEngine {
            }

            if (policyChanged) {
                onLocalPolicyChanged(policyDefinition, enforcingAdmin, userId);
                onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
            }

            // For a removePolicy to be enforced, it means no current policy exists
@@ -348,7 +350,7 @@ final class DevicePolicyEngine {
    /**
     * Enforces the new policy and notifies relevant admins.
     */
    private <V> void onLocalPolicyChanged(
    private <V> void onLocalPolicyChangedLocked(
            @NonNull PolicyDefinition<V> policyDefinition,
            @NonNull EnforcingAdmin enforcingAdmin,
            int userId) {
@@ -358,7 +360,7 @@ final class DevicePolicyEngine {
                policyDefinition, localPolicyState.getCurrentResolvedPolicy(), userId);

        // Send policy updates to admins who've set it locally
        sendPolicyChangedToAdmins(
        sendPolicyChangedToAdminsLocked(
                localPolicyState,
                enforcingAdmin,
                policyDefinition,
@@ -369,7 +371,7 @@ final class DevicePolicyEngine {
        // Send policy updates to admins who've set it globally
        if (hasGlobalPolicyLocked(policyDefinition)) {
            PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
            sendPolicyChangedToAdmins(
            sendPolicyChangedToAdminsLocked(
                    globalPolicyState,
                    enforcingAdmin,
                    policyDefinition,
@@ -424,7 +426,7 @@ final class DevicePolicyEngine {
            // the data structures.
            if (!skipEnforcePolicy) {
                if (policyChanged) {
                    onGlobalPolicyChanged(policyDefinition, enforcingAdmin);
                    onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
                }

                boolean policyAppliedGlobally = Objects.equals(
@@ -473,7 +475,7 @@ final class DevicePolicyEngine {
            boolean policyChanged = policyState.removePolicy(enforcingAdmin);

            if (policyChanged) {
                onGlobalPolicyChanged(policyDefinition, enforcingAdmin);
                onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
            }

            applyGlobalPolicyOnUsersWithLocalPoliciesLocked(policyDefinition, enforcingAdmin,
@@ -499,7 +501,7 @@ final class DevicePolicyEngine {
    /**
     * Enforces the new policy globally and notifies relevant admins.
     */
    private <V> void onGlobalPolicyChanged(
    private <V> void onGlobalPolicyChangedLocked(
            @NonNull PolicyDefinition<V> policyDefinition,
            @NonNull EnforcingAdmin enforcingAdmin) {
        PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
@@ -507,7 +509,7 @@ final class DevicePolicyEngine {
        enforcePolicy(policyDefinition, policyState.getCurrentResolvedPolicy(),
                UserHandle.USER_ALL);

        sendPolicyChangedToAdmins(
        sendPolicyChangedToAdminsLocked(
                policyState,
                enforcingAdmin,
                policyDefinition,
@@ -552,7 +554,7 @@ final class DevicePolicyEngine {
                        policyDefinition,
                        localPolicyState.getCurrentResolvedPolicy(),
                        userId);
                sendPolicyChangedToAdmins(
                sendPolicyChangedToAdminsLocked(
                        localPolicyState,
                        enforcingAdmin,
                        policyDefinition,
@@ -745,6 +747,7 @@ final class DevicePolicyEngine {
    }

    <V> void transferPolicies(EnforcingAdmin oldAdmin, EnforcingAdmin newAdmin) {
        synchronized (mLock) {
            Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
            for (PolicyKey policy : globalPolicies) {
                PolicyState<?> policyState = mGlobalPolicies.get(policy);
@@ -772,7 +775,7 @@ final class DevicePolicyEngine {
                    }
                }
            }

        }
        removePoliciesForAdmin(oldAdmin);
    }

@@ -836,7 +839,7 @@ final class DevicePolicyEngine {
            mLocalPolicies.get(userId).put(
                    policyDefinition.getPolicyKey(), new PolicyState<>(policyDefinition));
        }
        return getPolicyState(mLocalPolicies.get(userId), policyDefinition);
        return getPolicyStateLocked(mLocalPolicies.get(userId), policyDefinition);
    }

    private <V> void removeLocalPolicyStateLocked(
@@ -858,14 +861,14 @@ final class DevicePolicyEngine {
            mGlobalPolicies.put(
                    policyDefinition.getPolicyKey(), new PolicyState<>(policyDefinition));
        }
        return getPolicyState(mGlobalPolicies, policyDefinition);
        return getPolicyStateLocked(mGlobalPolicies, policyDefinition);
    }

    private <V> void removeGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) {
        mGlobalPolicies.remove(policyDefinition.getPolicyKey());
    }

    private static <V> PolicyState<V> getPolicyState(
    private static <V> PolicyState<V> getPolicyStateLocked(
            Map<PolicyKey, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition) {
        try {
            // This will not throw an exception because policyDefinition is of type V, so unless
@@ -935,7 +938,7 @@ final class DevicePolicyEngine {
    }

    // TODO(b/261430877): Finalise the decision on which admins to send the updates to.
    private <V> void sendPolicyChangedToAdmins(
    private <V> void sendPolicyChangedToAdminsLocked(
            PolicyState<V> policyState,
            EnforcingAdmin callingAdmin,
            PolicyDefinition<V> policyDefinition,
@@ -1210,17 +1213,19 @@ final class DevicePolicyEngine {
            if (parentInfo == null || parentInfo.getUserHandle().getIdentifier() == userId) {
                return;
            }
            synchronized (mLock) {
                if (!mLocalPolicies.contains(parentInfo.getUserHandle().getIdentifier())) {
                    return;
                }
                for (Map.Entry<PolicyKey, PolicyState<?>> entry : mLocalPolicies.get(
                        parentInfo.getUserHandle().getIdentifier()).entrySet()) {
                enforcePolicyOnUser(userId, entry.getValue());
                    enforcePolicyOnUserLocked(userId, entry.getValue());
                }
            }
        });
    }

    private <V> void enforcePolicyOnUser(int userId, PolicyState<V> policyState) {
    private <V> void enforcePolicyOnUserLocked(int userId, PolicyState<V> policyState) {
        if (!policyState.getPolicyDefinition().isInheritable()) {
            return;
        }
@@ -1239,6 +1244,7 @@ final class DevicePolicyEngine {
     */
    @NonNull
    DevicePolicyState getDevicePolicyState() {
        synchronized (mLock) {
            Map<UserHandle, Map<PolicyKey, android.app.admin.PolicyState<?>>> policies =
                    new HashMap<>();
            for (int i = 0; i < mLocalPolicies.size(); i++) {
@@ -1260,12 +1266,14 @@ final class DevicePolicyEngine {
            }
            return new DevicePolicyState(policies);
        }
    }


    /**
     * Removes all local and global policies set by that admin.
     */
    void removePoliciesForAdmin(EnforcingAdmin admin) {
        synchronized (mLock) {
            Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
            for (PolicyKey policy : globalPolicies) {
                PolicyState<?> policyState = mGlobalPolicies.get(policy);
@@ -1287,11 +1295,13 @@ final class DevicePolicyEngine {
                }
            }
        }
    }

    /**
     * Removes all local policies for the provided {@code userId}.
     */
    private void removeLocalPoliciesForUser(int userId) {
        synchronized (mLock) {
            if (!mLocalPolicies.contains(userId)) {
                // No policies on user
                return;
@@ -1310,6 +1320,7 @@ final class DevicePolicyEngine {

            mLocalPolicies.remove(userId);
        }
    }

    /**
     * Removes all local and global policies for admins installed in the provided
@@ -1376,7 +1387,7 @@ final class DevicePolicyEngine {
     */
    private void updateDeviceAdminServiceOnPolicyRemoveLocked(
            @NonNull EnforcingAdmin enforcingAdmin) {
        if (doesAdminHavePolicies(enforcingAdmin)) {
        if (doesAdminHavePoliciesLocked(enforcingAdmin)) {
            return;
        }
        int userId = enforcingAdmin.getUserId();
@@ -1399,7 +1410,7 @@ final class DevicePolicyEngine {
                /* actionForLog= */ "policy-removed");
    }

    private boolean doesAdminHavePolicies(@NonNull EnforcingAdmin enforcingAdmin) {
    private boolean doesAdminHavePoliciesLocked(@NonNull EnforcingAdmin enforcingAdmin) {
        for (PolicyKey policy : mGlobalPolicies.keySet()) {
            PolicyState<?> policyState = mGlobalPolicies.get(policy);
            if (policyState.getPoliciesSetByAdmins().containsKey(enforcingAdmin)) {
@@ -1420,14 +1431,18 @@ final class DevicePolicyEngine {

    @NonNull
    private Set<EnforcingAdmin> getEnforcingAdminsOnUser(int userId) {
        synchronized (mLock) {
            return mEnforcingAdmins.contains(userId)
                    ? mEnforcingAdmins.get(userId) : Collections.emptySet();
        }
    }

    private void write() {
        synchronized (mLock) {
            Log.d(TAG, "Writing device policies to file.");
            new DevicePoliciesReaderWriter().writeToFileLocked();
        }
    }

    // TODO(b/256852787): trigger resolving logic after loading policies as roles are recalculated
    //  and could result in a different enforced policy
@@ -1436,11 +1451,11 @@ final class DevicePolicyEngine {
        synchronized (mLock) {
            clear();
            new DevicePoliciesReaderWriter().readFromFileLocked();
            reapplyAllPolicies();
            reapplyAllPoliciesLocked();
        }
    }

    private <V> void reapplyAllPolicies() {
    private <V> void reapplyAllPoliciesLocked() {
        for (PolicyKey policy : mGlobalPolicies.keySet()) {
            PolicyState<?> policyState = mGlobalPolicies.get(policy);
            // Policy definition and value will always be of the same type
@@ -1470,11 +1485,9 @@ final class DevicePolicyEngine {
     * <p>Note that this doesn't clear any enforcements, it only clears the data structures.
     */
    void clearAllPolicies() {
        synchronized (mLock) {
        clear();
        write();
    }
    }
    private void clear() {
        synchronized (mLock) {
            mGlobalPolicies.clear();
+2 −1
Original line number Diff line number Diff line
@@ -2093,7 +2093,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        mUserData = new SparseArray<>();
        mOwners = makeOwners(injector, pathProvider);
        mDevicePolicyEngine = new DevicePolicyEngine(mContext, mDeviceAdminServiceController);
        mDevicePolicyEngine = new DevicePolicyEngine(
                mContext, mDeviceAdminServiceController, getLockObject());
        if (!mHasFeature) {
            // Skip the rest of the initialization