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

Commit 458d399c authored by Victor Gabriel Savu's avatar Victor Gabriel Savu
Browse files

Implement setPolicy in DPMS

Implement a first version of setPolicy in DPMS. It can now handle the
scope parameter and applies the default value.

A more generic implementation will be added in later CLs, currently only
supports SCREEN_CAPTURE_DISABLED.

Bug: 434655549
Fixed: 434615264
Flag: android.app.admin.flags.policy_streamlining
Test: CTS
Change-Id: I75d23509030bad725865843503607a97c6e53630
parent c7749aeb
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -18595,18 +18595,27 @@ public class DevicePolicyManager {
            @Nullable T value) {
        throwIfParentInstance("setPolicy");
        if (mService != null) {
            // TODO(b/434655549): Implement as a generic handler.
            if (id.equals(PolicyIdentifier.SCREEN_CAPTURE_DISABLED)) {
                if (value == null) return; // No way to clear the policy.
                // TODO(b/434615264): Actually use the scope here.
                setScreenCaptureDisabled(null, (Boolean) value);
            } else {
                throw new IllegalArgumentException("Unhandled policy " + id);
            try {
                mService.setPolicy(mContext.getPackageName(), id.getId(), scope,
                        policyValueToTransport(value));
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
    @Nullable
    private static PolicyValueTransport policyValueToTransport(@Nullable Object value) {
        return switch (value) {
            case null -> null;
            case Integer i -> PolicyValueTransport.integerField(i);
            case Boolean b -> PolicyValueTransport.booleanField(b);
            default -> throw new IllegalArgumentException(
                    "Type of policy is not supported: " + value + "(" + value.getClass().getName()
                            + ")");
        };
    }
    /**
     * Template free version of setPolicy for booleans.
     *
+3 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import android.telephony.data.ApnSetting;
import com.android.internal.infra.AndroidFuture;
import android.app.admin.DevicePolicyState;
import android.app.admin.EnforcingAdmin;
import android.app.admin.PolicyValueTransport;

import java.util.List;

@@ -654,4 +655,6 @@ interface IDevicePolicyManager {

    void setAppFunctionsPolicy(String callerPackageName, int policy);
    int getAppFunctionsPolicy(String callerPackageName, int userId);

    void setPolicy(in String callerPackageName, in String policy, in int scope, in PolicyValueTransport value);
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app.admin;

/**
 * Internal IPC to send a policy value over the wire.
 * Currently only supports a limited set of built-in types.
 *
 * {@hide}
 */
union PolicyValueTransport {
    int integerField;
    boolean booleanField;
}
 No newline at end of file
+75 −0
Original line number Diff line number Diff line
@@ -146,6 +146,8 @@ import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANT
import static android.app.admin.DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED;
import static android.app.admin.DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY;
import static android.app.admin.DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT;
import static android.app.admin.DevicePolicyManager.POLICY_SCOPE_DEVICE;
import static android.app.admin.DevicePolicyManager.POLICY_SCOPE_USER;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OFF;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
@@ -328,9 +330,11 @@ import android.app.admin.ParcelableGranteeMap;
import android.app.admin.ParcelableResource;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.app.admin.PolicyIdentifier;
import android.app.admin.PolicyKey;
import android.app.admin.PolicySizeVerifier;
import android.app.admin.PolicyValue;
import android.app.admin.PolicyValueTransport;
import android.app.admin.PreferentialNetworkServiceConfig;
import android.app.admin.SecurityLog;
import android.app.admin.SecurityLog.SecurityEvent;
@@ -24762,4 +24766,75 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        return Binder.withCleanCallingIdentity(() -> getHeadlessDeviceOwnerModeForDeviceOwner());
    }
    private void setScreenCaptureDisabled(CallerIdentity caller, int scope, Boolean disabled) {
        if (scope != POLICY_SCOPE_DEVICE && scope != POLICY_SCOPE_USER) {
            throw new IllegalArgumentException("Invalid scope " + scope);
        }
        mPermissions.enforce(MANAGE_DEVICE_POLICY_SCREEN_CAPTURE, caller);
        EnforcingAdmin admin = getEnforcingAdmin(caller);
        if (scope == POLICY_SCOPE_DEVICE && !isDefaultDeviceOwner(caller)
                && !isProfileOwnerOfOrganizationOwnedDevice(caller)) {
            throw new SecurityException(
                    "Caller must be a device owner or profile owner of an organization-owned "
                            + "managed profile to be able to set the policy with "
                            + "POLICY_SCOPE_DEVICE.");
        }
        // Clearing is done by false.
        if (disabled == null) {
            disabled = false;
        }
        switch (scope) {
            case POLICY_SCOPE_DEVICE:
                if (disabled) {
                    mDevicePolicyEngine.setGlobalPolicy(PolicyDefinition.SCREEN_CAPTURE_DISABLED,
                            admin,
                            new BooleanPolicyValue(disabled));
                } else {
                    mDevicePolicyEngine.removeGlobalPolicy(PolicyDefinition.SCREEN_CAPTURE_DISABLED,
                            admin);
                }
                break;
            case POLICY_SCOPE_USER:
                int userId = caller.getUserId();
                if (disabled) {
                    mDevicePolicyEngine.setLocalPolicy(PolicyDefinition.SCREEN_CAPTURE_DISABLED,
                            admin,
                            new BooleanPolicyValue(disabled), userId);
                } else {
                    mDevicePolicyEngine.removeLocalPolicy(PolicyDefinition.SCREEN_CAPTURE_DISABLED,
                            admin, userId);
                }
                break;
            default:
                throw new IllegalArgumentException(
                        "SCREEN_CAPTURE_DISABLED only supports POLICY_SCOPE_DEVICE and "
                        + "POLICY_SCOPE_USER");
        }
    }
    @Override
    public void setPolicy(String callerPackageName, String id, int scope,
            PolicyValueTransport value) {
        if (!mHasFeature) {
            return;
        }
        CallerIdentity caller = getCallerIdentity(callerPackageName);
        Binder.withCleanCallingIdentity(() -> {
            if (id.equals(PolicyIdentifier.SCREEN_CAPTURE_DISABLED.getId())) {
                if (value.getTag() != PolicyValueTransport.Tag.booleanField) {
                    throw new IllegalArgumentException(
                            "SCREEN_CAPTURE_DISABLED requires a Boolean value");
                }
                setScreenCaptureDisabled(caller, scope, value.getBooleanField());
            } else {
                throw new IllegalArgumentException("Unhandled policy " + id);
            }
        });
    }
}