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

Commit 3ce8050d authored by Victor Gabriel Savu's avatar Victor Gabriel Savu Committed by Android (Google) Code Review
Browse files

Merge "Implement setPolicy in DPMS" into main

parents 0111e96d 458d399c
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);
            }
        });
    }
}