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

Commit a97ef4e7 authored by Rafael Prado's avatar Rafael Prado
Browse files

Add support for async policy enforcement in PolicyDefinition.

Test: PRESUBMIT - No new feature effectivelly to be tested.
Flag: EXEMPT No-op refactoring.
Bug: 369141952
Bug: 336297680
Change-Id: Ieb971844058db8068f65aed31422fc361e6b18d2
parent 1c3a99ad
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);
        });
    }
}