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

Commit 83691cc8 authored by Rafael Prado's avatar Rafael Prado Committed by Android (Google) Code Review
Browse files

Merge "Add support for async policy enforcement in PolicyDefinition." into main

parents 7ed0e830 a97ef4e7
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

/**
 * Class responsible for setting, resolving, and enforcing policies set by multiple management
@@ -1030,11 +1031,11 @@ final class DevicePolicyEngine {
        }
    }

    private <V> void enforcePolicy(PolicyDefinition<V> policyDefinition,
    private <V> CompletableFuture<Boolean> enforcePolicy(PolicyDefinition<V> policyDefinition,
            @Nullable PolicyValue<V> policyValue, int userId) {
        // null policyValue means remove any enforced policies, ensure callbacks handle this
        // properly
        policyDefinition.enforcePolicy(
        return policyDefinition.enforcePolicy(
                policyValue == null ? null : policyValue.getValue(), mContext, userId);
    }

+9 −6
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

final class PolicyDefinition<V> {

@@ -504,7 +505,8 @@ final class PolicyDefinition<V> {
    private final int mPolicyFlags;
    // A function that accepts  policy to apply, context, userId, callback arguments, and returns
    // true if the policy has been enforced successfully.
    private final QuadFunction<V, Context, Integer, PolicyKey, Boolean> mPolicyEnforcerCallback;
    private final QuadFunction<V, Context, Integer, PolicyKey, CompletableFuture<Boolean>>
            mPolicyEnforcerCallback;
    private final PolicySerializer<V> mPolicySerializer;

    private PolicyDefinition<V> createPolicyDefinition(PolicyKey key) {
@@ -574,7 +576,7 @@ final class PolicyDefinition<V> {
        return mResolutionMechanism.resolve(adminsPolicy);
    }

    boolean enforcePolicy(@Nullable V value, Context context, int userId) {
    CompletableFuture<Boolean> enforcePolicy(@Nullable V value, Context context, int userId) {
        return mPolicyEnforcerCallback.apply(value, context, userId, mPolicyKey);
    }

@@ -592,7 +594,6 @@ final class PolicyDefinition<V> {
        POLICY_DEFINITIONS.put(key.getIdentifier(), definition);
    }


    /**
     * Callers must ensure that {@code policyType} have implemented an appropriate
     * {@link Object#equals} implementation.
@@ -600,7 +601,8 @@ final class PolicyDefinition<V> {
    private PolicyDefinition(
            @NonNull  PolicyKey key,
            ResolutionMechanism<V> resolutionMechanism,
            QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
            QuadFunction<V, Context, Integer, PolicyKey, CompletableFuture<Boolean>>
                    policyEnforcerCallback,
            PolicySerializer<V> policySerializer) {
        this(key, resolutionMechanism, POLICY_FLAG_NONE, policyEnforcerCallback, policySerializer);
    }
@@ -613,7 +615,8 @@ final class PolicyDefinition<V> {
            @NonNull PolicyKey policyKey,
            ResolutionMechanism<V> resolutionMechanism,
            int policyFlags,
            QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
            QuadFunction<V, Context, Integer, PolicyKey, CompletableFuture<Boolean>>
                    policyEnforcerCallback,
            PolicySerializer<V> policySerializer) {
        Objects.requireNonNull(policyKey);
        mPolicyKey = policyKey;
+55 −47
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import android.util.ArraySet;
import android.util.Slog;
import android.view.IWindowManager;

import com.android.internal.infra.AndroidFuture;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
@@ -65,6 +66,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@@ -73,33 +75,36 @@ final class PolicyEnforcerCallbacks {

    private static final String LOG_TAG = "PolicyEnforcerCallbacks";

    static <T> boolean noOp(T value, Context context, Integer userId, PolicyKey policyKey) {
        return true;
    static <T> CompletableFuture<Boolean> noOp(T value, Context context, Integer userId,
            PolicyKey policyKey) {
        return AndroidFuture.completedFuture(true);
    }

    static boolean setAutoTimezoneEnabled(@Nullable Boolean enabled, @NonNull Context context) {
    static CompletableFuture<Boolean> setAutoTimezoneEnabled(@Nullable Boolean enabled,
            @NonNull Context context) {
        if (!Flags.setAutoTimeZoneEnabledCoexistence()) {
            Slogf.w(LOG_TAG, "Trying to enforce setAutoTimezoneEnabled while flag is off.");
            return true;
            return AndroidFuture.completedFuture(true);
        }
        return Binder.withCleanCallingIdentity(() -> {
            Objects.requireNonNull(context);

            int value = enabled != null && enabled ? 1 : 0;
            return Settings.Global.putInt(
            return AndroidFuture.completedFuture(
                    Settings.Global.putInt(
                            context.getContentResolver(), Settings.Global.AUTO_TIME_ZONE,
                    value);
                    value));
        });
    }

    static boolean setPermissionGrantState(
    static CompletableFuture<Boolean> setPermissionGrantState(
            @Nullable Integer grantState, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        if (!Flags.setPermissionGrantStateCoexistence()) {
            Slogf.w(LOG_TAG, "Trying to enforce setPermissionGrantState while flag is off.");
            return true;
            return AndroidFuture.completedFuture(true);
        }
        return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
        return Binder.withCleanCallingIdentity(() -> {
            if (!(policyKey instanceof PackagePermissionPolicyKey)) {
                throw new IllegalArgumentException("policyKey is not of type "
                        + "PermissionGrantStatePolicyKey, passed in policyKey is: " + policyKey);
@@ -125,12 +130,13 @@ final class PolicyEnforcerCallbacks {
                    .setRuntimePermissionGrantStateByDeviceAdmin(context.getPackageName(),
                            permissionParams, context.getMainExecutor(), callback::trigger);
            try {
                return callback.await(20_000, TimeUnit.MILLISECONDS);
                return AndroidFuture.completedFuture(
                        callback.await(20_000, TimeUnit.MILLISECONDS));
            } catch (Exception e) {
                // TODO: add logging
                return false;
                return AndroidFuture.completedFuture(false);
            }
        }));
        });
    }

    @NonNull
@@ -149,23 +155,23 @@ final class PolicyEnforcerCallbacks {
        }
    }

    static boolean enforceSecurityLogging(
    static CompletableFuture<Boolean> enforceSecurityLogging(
            @Nullable Boolean value, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
        dpmi.enforceSecurityLoggingPolicy(Boolean.TRUE.equals(value));
        return true;
        return AndroidFuture.completedFuture(true);
    }

    static boolean enforceAuditLogging(
    static CompletableFuture<Boolean> enforceAuditLogging(
            @Nullable Boolean value, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
        dpmi.enforceAuditLoggingPolicy(Boolean.TRUE.equals(value));
        return true;
        return AndroidFuture.completedFuture(true);
    }

    static boolean setLockTask(
    static CompletableFuture<Boolean> setLockTask(
            @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
        List<String> packages = Collections.emptyList();
        int flags = LockTaskPolicy.DEFAULT_LOCK_TASK_FLAG;
@@ -175,7 +181,7 @@ final class PolicyEnforcerCallbacks {
        }
        DevicePolicyManagerService.updateLockTaskPackagesLocked(context, packages, userId);
        DevicePolicyManagerService.updateLockTaskFeaturesLocked(flags, userId);
        return true;
        return AndroidFuture.completedFuture(true);
    }


@@ -187,8 +193,8 @@ final class PolicyEnforcerCallbacks {
     * rely on the POLICY_FLAG_SKIP_ENFORCEMENT_IF_UNCHANGED flag so DPE only invokes this callback
     * when the policy is set, and not during system boot or other situations.
     */
    static boolean setApplicationRestrictions(Bundle bundle, Context context, Integer userId,
            PolicyKey policyKey) {
    static CompletableFuture<Boolean> setApplicationRestrictions(Bundle bundle, Context context,
            Integer userId, PolicyKey policyKey) {
        Binder.withCleanCallingIdentity(() -> {
            PackagePolicyKey key = (PackagePolicyKey) policyKey;
            String packageName = key.getPackageName();
@@ -198,7 +204,7 @@ final class PolicyEnforcerCallbacks {
            changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            context.sendBroadcastAsUser(changeIntent, UserHandle.of(userId));
        });
        return true;
        return AndroidFuture.completedFuture(true);
    }

    private static class BlockingCallback {
@@ -220,7 +226,7 @@ final class PolicyEnforcerCallbacks {
    // TODO: when a local policy exists for a user, this callback will be invoked for this user
    // individually as well as for USER_ALL. This can be optimized by separating local and global
    // enforcement in the policy engine.
    static boolean setUserControlDisabledPackages(
    static CompletableFuture<Boolean> setUserControlDisabledPackages(
            @Nullable Set<String> packages, Context context, int userId, PolicyKey policyKey) {
        Binder.withCleanCallingIdentity(() -> {
            PackageManagerInternal pmi =
@@ -246,7 +252,7 @@ final class PolicyEnforcerCallbacks {
                }
            }
        });
        return true;
        return AndroidFuture.completedFuture(true);
    }

    /** Handles USER_ALL expanding it into the list of all intact users. */
@@ -271,7 +277,7 @@ final class PolicyEnforcerCallbacks {
        }
    }

    static boolean addPersistentPreferredActivity(
    static CompletableFuture<Boolean> addPersistentPreferredActivity(
            @Nullable ComponentName preferredActivity, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        Binder.withCleanCallingIdentity(() -> {
@@ -297,13 +303,13 @@ final class PolicyEnforcerCallbacks {
                Slog.wtf(LOG_TAG, "Error adding/removing persistent preferred activity", re);
            }
        });
        return true;
        return AndroidFuture.completedFuture(true);
    }

    static boolean setUninstallBlocked(
    static CompletableFuture<Boolean> setUninstallBlocked(
            @Nullable Boolean uninstallBlocked, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
        return Binder.withCleanCallingIdentity(() -> {
            if (!(policyKey instanceof PackagePolicyKey)) {
                throw new IllegalArgumentException("policyKey is not of type "
                        + "PackagePolicyKey, passed in policyKey is: " + policyKey);
@@ -314,14 +320,14 @@ final class PolicyEnforcerCallbacks {
                    packageName,
                    uninstallBlocked != null && uninstallBlocked,
                    userId);
            return true;
        }));
            return AndroidFuture.completedFuture(true);
        });
    }

    static boolean setUserRestriction(
    static CompletableFuture<Boolean> setUserRestriction(
            @Nullable Boolean enabled, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
        return Binder.withCleanCallingIdentity(() -> {
            if (!(policyKey instanceof UserRestrictionPolicyKey)) {
                throw new IllegalArgumentException("policyKey is not of type "
                        + "UserRestrictionPolicyKey, passed in policyKey is: " + policyKey);
@@ -331,14 +337,14 @@ final class PolicyEnforcerCallbacks {
            UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
            userManager.setUserRestriction(
                    userId, parsedKey.getRestriction(), enabled != null && enabled);
            return true;
        }));
            return AndroidFuture.completedFuture(true);
        });
    }

    static boolean setApplicationHidden(
    static CompletableFuture<Boolean> setApplicationHidden(
            @Nullable Boolean hide, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
        return Binder.withCleanCallingIdentity(() -> {
            if (!(policyKey instanceof PackagePolicyKey)) {
                throw new IllegalArgumentException("policyKey is not of type "
                        + "PackagePolicyKey, passed in policyKey is: " + policyKey);
@@ -346,12 +352,13 @@ final class PolicyEnforcerCallbacks {
            PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey;
            String packageName = Objects.requireNonNull(parsedKey.getPackageName());
            IPackageManager packageManager = AppGlobals.getPackageManager();
            return packageManager.setApplicationHiddenSettingAsUser(
                    packageName, hide != null && hide, userId);
        }));
            return AndroidFuture.completedFuture(
                    packageManager.setApplicationHiddenSettingAsUser(
                            packageName, hide != null && hide, userId));
        });
    }

    static boolean setScreenCaptureDisabled(
    static CompletableFuture<Boolean> setScreenCaptureDisabled(
            @Nullable Boolean disabled, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        Binder.withCleanCallingIdentity(() -> {
@@ -363,10 +370,10 @@ final class PolicyEnforcerCallbacks {
                updateScreenCaptureDisabled();
            }
        });
        return true;
        return AndroidFuture.completedFuture(true);
    }

    static boolean setContentProtectionPolicy(
    static CompletableFuture<Boolean> setContentProtectionPolicy(
            @Nullable Integer value,
            @NonNull Context context,
            @UserIdInt Integer userId,
@@ -378,7 +385,7 @@ final class PolicyEnforcerCallbacks {
                        cacheImpl.setContentProtectionPolicy(userId, value);
                    }
                });
        return true;
        return AndroidFuture.completedFuture(true);
    }

    private static void updateScreenCaptureDisabled() {
@@ -393,7 +400,7 @@ final class PolicyEnforcerCallbacks {
        });
    }

    static boolean setPersonalAppsSuspended(
    static CompletableFuture<Boolean> setPersonalAppsSuspended(
            @Nullable Boolean suspended, @NonNull Context context, int userId,
            @NonNull PolicyKey policyKey) {
        Binder.withCleanCallingIdentity(() -> {
@@ -404,7 +411,7 @@ final class PolicyEnforcerCallbacks {
                        .unsuspendAdminSuspendedPackages(userId);
            }
        });
        return true;
        return AndroidFuture.completedFuture(true);
    }

    private static void suspendPersonalAppsInPackageManager(Context context, int userId) {
@@ -418,13 +425,14 @@ final class PolicyEnforcerCallbacks {
        }
    }

    static boolean setUsbDataSignalingEnabled(@Nullable Boolean value, @NonNull Context context) {
    static CompletableFuture<Boolean> setUsbDataSignalingEnabled(@Nullable Boolean value,
            @NonNull Context context) {
        return Binder.withCleanCallingIdentity(() -> {
            Objects.requireNonNull(context);

            boolean enabled = value == null || value;
            DevicePolicyManagerService.updateUsbDataSignal(context, enabled);
            return true;
            return AndroidFuture.completedFuture(true);
        });
    }
}