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

Commit ddbe98b0 authored by Ankita Vyas's avatar Ankita Vyas
Browse files

Apply inheritable policies from parent to child profile.

- Child profile should have user property inheritDevicePolicyFromParent
- Applies policies to both existing and newly created profiles.

Test: manual
Bug: 251401809
Change-Id: I0a4a5cac99c129ee76635236ab5f4457c39d66ec
parent b3b927f5
Loading
Loading
Loading
Loading
+87 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_CONFLICTING_AD
import static android.app.admin.PolicyUpdateResult.RESULT_SUCCESS;
import static android.app.admin.PolicyUpdateResult.RESULT_SUCCESS;
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_TARGET_USER_ID;
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_TARGET_USER_ID;
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_UPDATE_RESULT_KEY;
import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_UPDATE_RESULT_KEY;
import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT;


import android.Manifest;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.NonNull;
@@ -32,6 +33,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserProperties;
import android.os.Binder;
import android.os.Binder;
import android.os.Bundle;
import android.os.Bundle;
import android.os.Environment;
import android.os.Environment;
@@ -149,6 +151,8 @@ final class DevicePolicyEngine {
            updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
            updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);


            write();
            write();

            applyToInheritableProfiles(policyDefinition, enforcingAdmin, value, userId);
        }
        }
    }
    }


@@ -200,9 +204,51 @@ final class DevicePolicyEngine {
            updateDeviceAdminServiceOnPolicyRemoveLocked(enforcingAdmin);
            updateDeviceAdminServiceOnPolicyRemoveLocked(enforcingAdmin);


            write();
            write();

            applyToInheritableProfiles(policyDefinition, enforcingAdmin, /*value */ null, userId);
        }
        }
    }
    }


    /**
     * If any of child user has property {@link UserProperties#INHERIT_DEVICE_POLICY_FROM_PARENT}
     * set then propagate the policy to it if value is not null
     * else remove the policy from child.
     */
    private <V> void applyToInheritableProfiles(PolicyDefinition<V> policyDefinition,
            EnforcingAdmin enforcingAdmin, V value, int userId) {
        if (policyDefinition.isInheritable()) {
            Binder.withCleanCallingIdentity(() -> {
                List<UserInfo> userInfos = mUserManager.getProfiles(userId);
                for (UserInfo childUserInfo : userInfos) {
                    int childUserId = childUserInfo.getUserHandle().getIdentifier();
                    if (isProfileOfUser(childUserId, userId)
                            && isInheritDevicePolicyFromParent(childUserInfo)) {
                        if (value != null) {
                            setLocalPolicy(policyDefinition, enforcingAdmin, value, childUserId);
                        } else {
                            removeLocalPolicy(policyDefinition, enforcingAdmin, childUserId);
                        }
                    }
                }
            });
        }
    }

    /**
     * Checks if given parentUserId is direct parent of childUserId.
     */
    private boolean isProfileOfUser(int childUserId, int parentUserId) {
        UserInfo parentInfo = mUserManager.getProfileParent(childUserId);
        return childUserId != parentUserId && parentInfo != null
                && parentInfo.getUserHandle().getIdentifier() == parentUserId;
    }

    private boolean isInheritDevicePolicyFromParent(UserInfo userInfo) {
        UserProperties userProperties = mUserManager.getUserProperties(userInfo.getUserHandle());
        return userProperties != null && mUserManager.getUserProperties(userInfo.getUserHandle())
                .getInheritDevicePolicy() == INHERIT_DEVICE_POLICY_FROM_PARENT;
    }

    /**
    /**
     * Enforces the new policy and notifies relevant admins.
     * Enforces the new policy and notifies relevant admins.
     */
     */
@@ -688,6 +734,47 @@ final class DevicePolicyEngine {
        }
        }
    }
    }


    void handleUserCreated(UserInfo user) {
        enforcePoliciesOnInheritableProfilesIfApplicable(user);
    }

    private void enforcePoliciesOnInheritableProfilesIfApplicable(UserInfo user) {
        if (!user.isProfile()) {
            return;
        }

        Binder.withCleanCallingIdentity(() -> {
            UserProperties userProperties = mUserManager.getUserProperties(user.getUserHandle());
            if (userProperties == null || userProperties.getInheritDevicePolicy()
                    != INHERIT_DEVICE_POLICY_FROM_PARENT) {
                return;
            }

            int userId = user.id;
            // Apply local policies present on parent to newly created child profile.
            UserInfo parentInfo = mUserManager.getProfileParent(userId);
            if (parentInfo == null || parentInfo.getUserHandle().getIdentifier() == userId) return;

            for (Map.Entry<PolicyKey, PolicyState<?>> entry : mLocalPolicies.get(
                    parentInfo.getUserHandle().getIdentifier()).entrySet()) {
                enforcePolicyOnUser(userId, entry.getValue());
            }
        });
    }

    private <V> void enforcePolicyOnUser(int userId, PolicyState<V> policyState) {
        if (!policyState.getPolicyDefinition().isInheritable()) {
            return;
        }
        for (Map.Entry<EnforcingAdmin, V> enforcingAdminEntry :
                policyState.getPoliciesSetByAdmins().entrySet()) {
            setLocalPolicy(policyState.getPolicyDefinition(),
                    enforcingAdminEntry.getKey(),
                    enforcingAdminEntry.getValue(),
                    userId);
        }
    }

    /**
    /**
     * Handles internal state related to a user getting started.
     * Handles internal state related to a user getting started.
     */
     */
+5 −0
Original line number Original line Diff line number Diff line
@@ -11218,6 +11218,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
        }
        final int userId = user.id;
        final int userId = user.id;
        if (isCoexistenceFlagEnabled()) {
            mDevicePolicyEngine.handleUserCreated(user);
        }
        if (token != null) {
        if (token != null) {
            synchronized (getLockObject()) {
            synchronized (getLockObject()) {
                if (mPendingUserCreatedCallbackTokens.contains(token)) {
                if (mPendingUserCreatedCallbackTokens.contains(token)) {
+10 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,9 @@ final class PolicyDefinition<V> {
    // Only use this flag if a policy can not be applied globally.
    // Only use this flag if a policy can not be applied globally.
    private static final int POLICY_FLAG_LOCAL_ONLY_POLICY = 1 << 1;
    private static final int POLICY_FLAG_LOCAL_ONLY_POLICY = 1 << 1;


    // Only use this flag if a policy is inheritable by child profile from parent.
    private static final int POLICY_FLAG_INHERITABLE = 1 << 2;

    private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
    private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
            List.of(false, true));
            List.of(false, true));


@@ -210,6 +213,13 @@ final class PolicyDefinition<V> {
        return (mPolicyFlags & POLICY_FLAG_LOCAL_ONLY_POLICY) != 0;
        return (mPolicyFlags & POLICY_FLAG_LOCAL_ONLY_POLICY) != 0;
    }
    }


    /**
     * Returns {@code true} if the policy is inheritable by child profiles.
     */
    boolean isInheritable() {
        return (mPolicyFlags & POLICY_FLAG_INHERITABLE) != 0;
    }

    @Nullable
    @Nullable
    V resolvePolicy(LinkedHashMap<EnforcingAdmin, V> adminsPolicy) {
    V resolvePolicy(LinkedHashMap<EnforcingAdmin, V> adminsPolicy) {
        return mResolutionMechanism.resolve(adminsPolicy);
        return mResolutionMechanism.resolve(adminsPolicy);
+4 −0
Original line number Original line Diff line number Diff line
@@ -216,4 +216,8 @@ final class PolicyState<V> {
        }
        }
        return new PolicyState<V>(policyDefinition, policiesSetByAdmins, currentResolvedPolicy);
        return new PolicyState<V>(policyDefinition, policiesSetByAdmins, currentResolvedPolicy);
    }
    }

    PolicyDefinition<V> getPolicyDefinition() {
        return mPolicyDefinition;
    }
}
}