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

Commit 1450eda9 authored by Kholoud Mohamed's avatar Kholoud Mohamed Committed by Android (Google) Code Review
Browse files

Merge "Add proper gating logic for coexistence"

parents 05277989 9df8ff2f
Loading
Loading
Loading
Loading
+56 −16
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ 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_UPDATE_RESULT_KEY;
import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT;
import static android.provider.DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER;

import android.Manifest;
import android.annotation.NonNull;
@@ -42,6 +43,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.AtomicFile;
import android.util.Log;
import android.util.SparseArray;
@@ -74,6 +76,9 @@ import java.util.Set;
final class DevicePolicyEngine {
    static final String TAG = "DevicePolicyEngine";

    private static final String ENABLE_COEXISTENCE_FLAG = "enable_coexistence";
    private static final boolean DEFAULT_ENABLE_COEXISTENCE_FLAG = true;

    private final Context mContext;
    private final UserManager mUserManager;

@@ -820,7 +825,7 @@ final class DevicePolicyEngine {
     * each admin. Global policies are returned under {@link UserHandle#ALL}.
     */
    @NonNull
    DevicePolicyState getParcelablePoliciesStateMap() {
    DevicePolicyState getDevicePolicyState() {
        Map<UserHandle, Map<PolicyKey, android.app.admin.PolicyState<?>>> policies =
                new HashMap<>();
        for (int i = 0; i < mLocalPolicies.size(); i++) {
@@ -869,11 +874,6 @@ final class DevicePolicyEngine {
    private void updateDeviceAdminServiceOnPolicyAddLocked(@NonNull EnforcingAdmin enforcingAdmin) {
        int userId = enforcingAdmin.getUserId();

        // A connection is established with DPCs as soon as they are provisioned, so no need to
        // connect when a policy is set.
        if (enforcingAdmin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
            return;
        }
        if (mEnforcingAdmins.contains(userId)
                && mEnforcingAdmins.get(userId).contains(enforcingAdmin)) {
            return;
@@ -884,6 +884,11 @@ final class DevicePolicyEngine {
        }
        mEnforcingAdmins.get(enforcingAdmin.getUserId()).add(enforcingAdmin);

        // A connection is established with DPCs as soon as they are provisioned, so no need to
        // connect when a policy is set.
        if (enforcingAdmin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
            return;
        }
        mDeviceAdminServiceController.startServiceForAdmin(
                enforcingAdmin.getPackageName(),
                userId,
@@ -896,18 +901,10 @@ final class DevicePolicyEngine {
     */
    private void updateDeviceAdminServiceOnPolicyRemoveLocked(
            @NonNull EnforcingAdmin enforcingAdmin) {
        // TODO(b/263364434): centralise handling in one place.
        // DPCs rely on a constant connection being established as soon as they are provisioned,
        // so we shouldn't disconnect it even if they no longer have policies set.
        if (enforcingAdmin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
            return;
        }
        if (doesAdminHavePolicies(enforcingAdmin)) {
            return;
        }

        int userId = enforcingAdmin.getUserId();

        if (mEnforcingAdmins.contains(userId)) {
            mEnforcingAdmins.get(userId).remove(enforcingAdmin);
            if (mEnforcingAdmins.get(userId).isEmpty()) {
@@ -915,6 +912,12 @@ final class DevicePolicyEngine {
            }
        }

        // TODO(b/263364434): centralise handling in one place.
        // DPCs rely on a constant connection being established as soon as they are provisioned,
        // so we shouldn't disconnect it even if they no longer have policies set.
        if (enforcingAdmin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
            return;
        }
        mDeviceAdminServiceController.stopServiceForAdmin(
                enforcingAdmin.getPackageName(),
                userId,
@@ -968,14 +971,51 @@ final class DevicePolicyEngine {
        }
    }

    // TODO: we need to listen for user removal and package removal and update out internal policy
    //  map and enforcing admins for this is be accurate.
    boolean hasActivePolicies() {
        return mEnforcingAdmins.size() > 0;
    }

    /**
     * Returns {@code true} if the coexistence flag is enabled or:
     * <ul>
     * <li>If the provided package is an admin with existing policies
     * <li>A new admin and no other admin have policies set
     * <li>More than one admin have policies set
     */
    boolean canAdminAddPolicies(String packageName, int userId) {
        if (isCoexistenceFlagEnabled()) {
            return true;
        }

        if (mEnforcingAdmins.contains(userId)
                && mEnforcingAdmins.get(userId).stream().anyMatch(admin ->
                admin.getPackageName().equals(packageName))) {
            return true;
        }

        int numOfEnforcingAdmins = 0;
        for (int i = 0; i < mEnforcingAdmins.size(); i++) {
            numOfEnforcingAdmins += mEnforcingAdmins.get(i).size();
        }
        return numOfEnforcingAdmins == 0 || numOfEnforcingAdmins > 1;
    }

    private boolean isCoexistenceFlagEnabled() {
        return DeviceConfig.getBoolean(
                NAMESPACE_DEVICE_POLICY_MANAGER,
                ENABLE_COEXISTENCE_FLAG,
                DEFAULT_ENABLE_COEXISTENCE_FLAG);
    }

    private class DevicePoliciesReaderWriter {
        private static final String DEVICE_POLICIES_XML = "device_policies.xml";
        private static final String DEVICE_POLICIES_XML = "device_policy_state.xml";
        private static final String TAG_LOCAL_POLICY_ENTRY = "local-policy-entry";
        private static final String TAG_GLOBAL_POLICY_ENTRY = "global-policy-entry";
        private static final String TAG_ADMINS_POLICY_ENTRY = "admins-policy-entry";
        private static final String TAG_ENFORCING_ADMINS_ENTRY = "enforcing-admins-entry";
        private static final String ATTR_USER_ID = "user-id";
        private static final String ATTR_POLICY_ID = "policy-id";

        private final File mFile;

+166 −40
Original line number Diff line number Diff line
@@ -745,11 +745,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    + "management app's authentication policy";
    private static final String NOT_SYSTEM_CALLER_MSG = "Only the system can %s";
    // ENABLE_DEVICE_POLICY_ENGINE_FLAG must be enabled before this could be enabled.
    private static final String PERMISSION_BASED_ACCESS_EXPERIMENT_FLAG =
            "enable_permission_based_access";
    private static final String ENABLE_COEXISTENCE_FLAG = "enable_coexistence";
    private static final boolean DEFAULT_VALUE_PERMISSION_BASED_ACCESS_FLAG = false;
    private static final boolean DEFAULT_ENABLE_COEXISTENCE_FLAG = false;
    // This must be enabled before PERMISSION_BASED_ACCESS_EXPERIMENT_FLAG is enabled, the reason
    // we're not just relying on PERMISSION_BASED_ACCESS_EXPERIMENT_FLAG to enable the policy engine
    // is that we might want to enable it before the permission changes are ready if we want to test
    // it on DPCs.
    // Once this is enabled, it can no longer be disabled in production
    private static final String ENABLE_DEVICE_POLICY_ENGINE_FLAG = "enable_device_policy_engine";
    private static final boolean DEFAULT_ENABLE_DEVICE_POLICY_ENGINE_FLAG = false;
    // TODO(b/258425381) remove the flag after rollout.
    private static final String KEEP_PROFILES_RUNNING_FLAG = "enable_keep_profiles_running";
@@ -1309,10 +1316,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    && (owner.getPackageName().equals(packageName))) {
                startOwnerService(userHandle, "package-broadcast");
            }
            if (isCoexistenceFlagEnabled()) {
            if (shouldMigrateToDevicePolicyEngine()) {
                migratePoliciesToDevicePolicyEngine();
            }
            if (isDevicePolicyEngineFlagEnabled()) {
                mDevicePolicyEngine.handlePackageChanged(packageName, userHandle);
            }
            // Persist updates if the removed package was an admin or delegate.
            if (removedAdmin || removedDelegate) {
                saveSettingsLocked(policy.mUserId);
@@ -2002,7 +2011,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
        mDeviceManagementResourcesProvider.load();
        if (isCoexistenceFlagEnabled()) {
        if (isDevicePolicyEngineFlagEnabled()) {
            mDevicePolicyEngine.load();
        }
@@ -3133,6 +3142,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                synchronized (getLockObject()) {
                    migrateToProfileOnOrganizationOwnedDeviceIfCompLocked();
                    applyProfileRestrictionsIfDeviceOwnerLocked();
                    // TODO: Is this the right place to trigger the migration?
                    if (shouldMigrateToDevicePolicyEngine()) {
                        migratePoliciesToDevicePolicyEngine();
                    }
                }
                maybeStartSecurityLogMonitorOnActivityManagerReady();
                break;
@@ -3341,7 +3355,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfigs);
        startOwnerService(userId, "start-user");
        if (isCoexistenceFlagEnabled()) {
        if (isDevicePolicyEngineFlagEnabled()) {
            mDevicePolicyEngine.handleStartUser(userId);
        }
    }
@@ -3366,7 +3380,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    void handleUnlockUser(int userId) {
        startOwnerService(userId, "unlock-user");
        if (isCoexistenceFlagEnabled()) {
        if (isDevicePolicyEngineFlagEnabled()) {
            mDevicePolicyEngine.handleUnlockUser(userId);
        }
    }
@@ -3378,7 +3392,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    void handleStopUser(int userId) {
        updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
        mDeviceAdminServiceController.stopServicesForUser(userId, /* actionForLog= */ "stop-user");
        if (isCoexistenceFlagEnabled()) {
        if (isDevicePolicyEngineFlagEnabled()) {
            mDevicePolicyEngine.handleStopUser(userId);
        }
    }
@@ -3486,7 +3500,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     * @param refreshing true = update an active admin, no error
     */
    @Override
    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
    public void setActiveAdmin(
            ComponentName adminReceiver, boolean refreshing, int userHandle) {
        if (!mHasFeature) {
            return;
        }
@@ -3503,6 +3518,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        synchronized (getLockObject()) {
            checkActiveAdminPrecondition(adminReceiver, info, policy);
            mInjector.binderWithCleanCallingIdentity(() -> {
                if (!canAddActiveAdminIfPolicyEngineEnabled(
                        adminReceiver.getPackageName(), userHandle)) {
                    throw new IllegalStateException("Can't add non-coexistable admin.");
                }
                final ActiveAdmin existingAdmin
                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
                if (!refreshing && existingAdmin != null) {
@@ -8246,7 +8266,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    caller));
        }
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            mDevicePolicyEngine.setGlobalPolicy(
                    PolicyDefinition.AUTO_TIMEZONE,
                    // TODO(b/260573124): add correct enforcing admin when permission changes are
@@ -10356,7 +10376,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller));
        final int userHandle = caller.getUserId();
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            mDevicePolicyEngine.setLocalPolicy(
                    PolicyDefinition.PERSISTENT_PREFERRED_ACTIVITY(filter),
                    EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
@@ -10394,7 +10414,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        final int userHandle = caller.getUserId();
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            clearPackagePersistentPreferredActivitiesFromPolicyEngine(
                    EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle),
                    packageName,
@@ -11348,7 +11368,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        final int userId = user.id;
        if (isCoexistenceFlagEnabled()) {
        if (isDevicePolicyEngineFlagEnabled()) {
            mDevicePolicyEngine.handleUserCreated(user);
        }
@@ -12378,7 +12398,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                || isFinancedDeviceOwner(caller)))
                || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL)));
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, DELEGATION_BLOCK_UNINSTALL)) {
            // TODO(b/260573124): Add correct enforcing admin when permission changes are
            //  merged, and don't forget to handle delegates! Enterprise admins assume
            //  component name isn't null.
@@ -12942,7 +12962,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES);
        }
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
                    who, caller.getUserId());
            if (packages.length == 0) {
@@ -12996,7 +13016,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            enforceCanCallLockTaskLocked(caller);
        }
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy(
                    PolicyDefinition.LOCK_TASK, userHandle);
            if (policy == null) {
@@ -13024,9 +13044,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
        final int userId = mInjector.userHandleGetCallingUserId();
        // TODO(b/260560985): This is not the right check, as the flag could be enabled but there
        //  could be an admin that hasn't targeted U.
        if (isCoexistenceFlagEnabled()) {
        // Is it ok to just check that no active policies exist currently?
        if (mDevicePolicyEngine.hasActivePolicies()) {
            LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy(
                    PolicyDefinition.LOCK_TASK, userId);
            if (policy == null) {
@@ -13060,7 +13079,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            enforceCanSetLockTaskFeaturesOnFinancedDevice(caller, flags);
            checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_FEATURES);
        }
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userHandle);
            LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicySetByAdmin(
                    PolicyDefinition.LOCK_TASK,
@@ -13101,7 +13120,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            enforceCanCallLockTaskLocked(caller);
        }
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            LockTaskPolicy policy = mDevicePolicyEngine.getResolvedPolicy(
                    PolicyDefinition.LOCK_TASK, userHandle);
            if (policy == null) {
@@ -14773,7 +14792,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                enforcePermissionGrantStateOnFinancedDevice(packageName, permission);
            }
        }
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, DELEGATION_PERMISSION_GRANT)) {
            mDevicePolicyEngine.setLocalPolicy(
                    PolicyDefinition.PERMISSION_GRANT(packageName, permission),
                    // TODO(b/260573124): Add correct enforcing admin when permission changes are
@@ -16183,6 +16202,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        // The removed admin might have disabled camera, so update user
        // restrictions.
        pushUserRestrictions(userHandle);
        // The removed admin might've been stopping the migration if it was targeting pre Android U
        if (shouldMigrateToDevicePolicyEngine()) {
            migratePoliciesToDevicePolicyEngine();
        }
    }
    @Override
@@ -18076,7 +18100,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        checkCanExecuteOrThrowUnsafe(
                DevicePolicyManager.OPERATION_SET_USER_CONTROL_DISABLED_PACKAGES);
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            Binder.withCleanCallingIdentity(() -> {
                if (packages.isEmpty()) {
                    removeUserControlDisabledPackages(caller);
@@ -18156,7 +18180,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller) || isProfileOwner(caller)
                || isFinancedDeviceOwner(caller));
        if (isCoexistenceEnabled(caller)) {
        if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
            // This retrieves the policy for the calling user only, DOs for example can't know
            // what's enforced globally or on another user.
            Set<String> packages = mDevicePolicyEngine.getResolvedPolicy(
@@ -20360,20 +20384,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                DEFAULT_VALUE_PERMISSION_BASED_ACCESS_FLAG);
    }
    // TODO(b/260560985): properly gate coexistence changes
    private boolean isCoexistenceEnabled(CallerIdentity caller) {
        return isCoexistenceFlagEnabled()
                && mInjector.isChangeEnabled(
                        ENABLE_COEXISTENCE_CHANGE, caller.getPackageName(), caller.getUserId());
    }
    private boolean isCoexistenceFlagEnabled() {
        return DeviceConfig.getBoolean(
                NAMESPACE_DEVICE_POLICY_MANAGER,
                ENABLE_COEXISTENCE_FLAG,
                DEFAULT_ENABLE_COEXISTENCE_FLAG);
    }
    private static boolean isKeepProfilesRunningFlagEnabled() {
        return DeviceConfig.getBoolean(
                NAMESPACE_DEVICE_POLICY_MANAGER,
@@ -20622,7 +20632,123 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    public DevicePolicyState getDevicePolicyState() {
        Preconditions.checkCallAuthorization(
                hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
        return mInjector.binderWithCleanCallingIdentity(() ->
                mDevicePolicyEngine.getParcelablePoliciesStateMap());
        return mInjector.binderWithCleanCallingIdentity(mDevicePolicyEngine::getDevicePolicyState);
    }
    // TODO(b/266808047): handle DeviceAdmin migration when there is no DPCs on the device
    private boolean shouldMigrateToDevicePolicyEngine() {
        return mInjector.binderWithCleanCallingIdentity(() -> {
            if (!isDevicePolicyEngineFlagEnabled()) {
                return false;
            }
            if (mOwners.isMigratedToPolicyEngine()) {
                return false;
            }
            // We're only checking if existing DPCs are not targeting U, regardless of what
            // DeviceAdmins are targeting, as they can access very limited APIs, and we'll ensure
            // that these APIs maintain the current behaviour of strictest applies.
            boolean hasDPCs = false;
            for (UserInfo userInfo : mUserManager.getUsers()) {
                List<ComponentName> activeAdmins = getActiveAdmins(userInfo.id);
                if (activeAdmins == null) {
                    continue;
                }
                for (ComponentName admin : activeAdmins) {
                    if ((isProfileOwner(admin, userInfo.id) || isDeviceOwner(admin, userInfo.id))) {
                        if (!mInjector.isChangeEnabled(ENABLE_COEXISTENCE_CHANGE,
                                admin.getPackageName(), userInfo.id)) {
                            return false;
                        }
                        hasDPCs = true;
                    }
                }
            }
            return hasDPCs;
        });
    }
    private void migratePoliciesToDevicePolicyEngine() {
        // TODO(b/258811766): add migration logic for each policy
        mOwners.markMigrationToPolicyEngine();
    }
    // TODO: This can actually accept an EnforcingAdmin that gets created in the permission check
    //  method.
    private boolean useDevicePolicyEngine(CallerIdentity caller, @Nullable String delegateScope) {
        if (!isCallerActiveAdminOrDelegate(caller, delegateScope)) {
            if (!isDevicePolicyEngineFlagEnabled()) {
                throw new IllegalStateException("Non DPC caller can't set device policies.");
            }
            if (hasDPCsNotSupportingCoexistence()) {
                throw new IllegalStateException("Non DPC caller can't set device policies with "
                        + "existing legacy admins on the device.");
            }
            return true;
        } else {
            return isDevicePolicyEngineFlagEnabled() && !hasDPCsNotSupportingCoexistence();
        }
    }
    private boolean isDevicePolicyEngineFlagEnabled() {
        return DeviceConfig.getBoolean(
                NAMESPACE_DEVICE_POLICY_MANAGER,
                ENABLE_DEVICE_POLICY_ENGINE_FLAG,
                DEFAULT_ENABLE_DEVICE_POLICY_ENGINE_FLAG);
    }
    private boolean hasDPCsNotSupportingCoexistence() {
        return mInjector.binderWithCleanCallingIdentity(() -> {
            for (UserInfo userInfo : mUserManager.getUsers()) {
                List<ComponentName> activeAdmins = getActiveAdmins(userInfo.id);
                if (activeAdmins == null) {
                    continue;
                }
                for (ComponentName admin : activeAdmins) {
                    if ((isProfileOwner(admin, userInfo.id) || isDeviceOwner(admin, userInfo.id))
                            && !mInjector.isChangeEnabled(ENABLE_COEXISTENCE_CHANGE,
                            admin.getPackageName(), userInfo.id)) {
                        return true;
                    }
                }
            }
            return false;
        });
    }
    // TODO: this can actually accept an EnforcingAdmin that gets created in the permission
    //  check method.
    private boolean isCallerActiveAdminOrDelegate(
            CallerIdentity caller, @Nullable String delegateScope) {
        return mInjector.binderWithCleanCallingIdentity(() -> {
            List<ComponentName> activeAdmins = getActiveAdmins(caller.getUserId());
            if (activeAdmins != null) {
                for (ComponentName admin : activeAdmins) {
                    if (admin.getPackageName().equals(caller.getPackageName())) {
                        return true;
                    }
                }
            }
            return delegateScope != null && isCallerDelegate(caller, delegateScope);
        });
    }
    // TODO(b/266808047): This will return false for DeviceAdmins not targetting U, which is
    //  inconsistent with the migration logic that allows migration with old DeviceAdmins.
    private boolean canAddActiveAdminIfPolicyEngineEnabled(String packageName, int userId) {
        if (!isDevicePolicyEngineFlagEnabled()) {
            return true;
        }
        if (hasDPCsNotSupportingCoexistence()) {
            return true;
        }
        if (mInjector.isChangeEnabled(ENABLE_COEXISTENCE_CHANGE, packageName, userId)) {
            // This will always return true unless we turn off coexistence, in which case it will
            // return true if no current admins exist, or more than one admin exist
            return mDevicePolicyEngine.canAdminAddPolicies(packageName, userId);
        }
        // Is it ok to just check that no active policies exist currently, or should we return false
        // if the policy engine was ever used?
        return !mDevicePolicyEngine.hasActivePolicies();
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -579,6 +579,19 @@ class Owners {
        }
    }

    void markMigrationToPolicyEngine() {
        synchronized (mData) {
            mData.mMigratedToPolicyEngine = true;
            mData.writeDeviceOwner();
        }
    }

    boolean isMigratedToPolicyEngine() {
        synchronized (mData) {
            return mData.mMigratedToPolicyEngine;
        }
    }

    @GuardedBy("mData")
    void pushToAppOpsLocked() {
        if (!mSystemReady) {
+13 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ class OwnersData {
    private static final String TAG_DEVICE_OWNER_TYPE = "device-owner-type";
    private static final String TAG_DEVICE_OWNER_PROTECTED_PACKAGES =
            "device-owner-protected-packages";
    private static final String TAG_POLICY_ENGINE_MIGRATION = "policy-engine-migration";

    private static final String ATTR_NAME = "name";
    private static final String ATTR_PACKAGE = "package";
@@ -84,6 +85,8 @@ class OwnersData {
            "isPoOrganizationOwnedDevice";
    private static final String ATTR_DEVICE_OWNER_TYPE_VALUE = "value";

    private static final String ATTR_MIGRATED_TO_POLICY_ENGINE = "migratedToPolicyEngine";

    // Internal state for the device owner package.
    OwnerInfo mDeviceOwner;
    int mDeviceOwnerUserId = UserHandle.USER_NULL;
@@ -109,6 +112,8 @@ class OwnersData {
    SystemUpdateInfo mSystemUpdateInfo;
    private final PolicyPathProvider mPathProvider;

    boolean mMigratedToPolicyEngine = false;

    OwnersData(PolicyPathProvider pathProvider) {
        mPathProvider = pathProvider;
    }
@@ -389,6 +394,11 @@ class OwnersData {
                }
                out.endTag(null, TAG_FREEZE_PERIOD_RECORD);
            }

            out.startTag(null, TAG_POLICY_ENGINE_MIGRATION);
            out.attributeBoolean(null, ATTR_MIGRATED_TO_POLICY_ENGINE, mMigratedToPolicyEngine);
            out.endTag(null, TAG_POLICY_ENGINE_MIGRATION);

        }

        @Override
@@ -444,6 +454,9 @@ class OwnersData {
                    }
                    mDeviceOwnerProtectedPackages.put(packageName, protectedPackages);
                    break;
                case TAG_POLICY_ENGINE_MIGRATION:
                    mMigratedToPolicyEngine = parser.getAttributeBoolean(
                            null, ATTR_MIGRATED_TO_POLICY_ENGINE, false);
                default:
                    Slog.e(TAG, "Unexpected tag: " + tag);
                    return false;