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

Commit 2108f19b authored by Rubin Xu's avatar Rubin Xu
Browse files

Disable Settings toggle if admin has set always-on VPN

If the admin has turned on always-on VPN, do not allow the user
to modify it. In order to distinguish between a user-initiated
always-on request and an admin-initiated one, DevicePolicyManager
needs to track what the admin has set, and provide getter to be
consumed by Settings code.

Bug: 137938969
Test: manually set always-on VPN and check Settings is disabled
Change-Id: Ief7454a2b66c487c23d06c2b4486a7107f8a385a
parent 003dedcc
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Activity;
@@ -5738,6 +5739,25 @@ public class DevicePolicyManager {
        return false;
    }
    /**
     * Returns whether the admin has enabled always-on VPN lockdown for the current user.
     *
     * Only callable by the system.
    * @hide
    */
    @UserHandleAware
    public boolean isAlwaysOnVpnLockdownEnabled() {
        throwIfParentInstance("isAlwaysOnVpnLockdownEnabled");
        if (mService != null) {
            try {
                return mService.isAlwaysOnVpnLockdownEnabledForUser(myUserId());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return false;
    }
    /**
     * Called by device or profile owner to query the set of packages that are allowed to access
     * the network directly when always-on VPN is in lockdown mode but not connected. Returns
@@ -5784,6 +5804,26 @@ public class DevicePolicyManager {
        return null;
    }
    /**
     * Returns the VPN package name if the admin has enabled always-on VPN on the current user,
     * or {@code null} if none is set.
     *
     * Only callable by the system.
     * @hide
     */
    @UserHandleAware
    public @Nullable String getAlwaysOnVpnPackage() {
        throwIfParentInstance("getAlwaysOnVpnPackage");
        if (mService != null) {
            try {
                return mService.getAlwaysOnVpnPackageForUser(myUserId());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        return null;
    }
    /**
     * Called by an application that is administering the device to disable all cameras on the
     * device, for this user. After setting this, no applications running as this user will be able
+2 −0
Original line number Diff line number Diff line
@@ -196,7 +196,9 @@ interface IDevicePolicyManager {

    boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist);
    String getAlwaysOnVpnPackage(in ComponentName who);
    String getAlwaysOnVpnPackageForUser(int userHandle);
    boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who);
    boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle);
    List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who);

    void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
+64 −4
Original line number Diff line number Diff line
@@ -1072,7 +1072,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps";
        private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off";
        private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline";
        private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package";
        private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
        DeviceAdminInfo info;
@@ -1201,6 +1202,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        // Time by which the profile should be turned on according to System.currentTimeMillis().
        long mProfileOffDeadline = 0;
        public String mAlwaysOnVpnPackage;
        public boolean mAlwaysOnVpnLockdown;
        ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
            info = _info;
@@ -1441,6 +1445,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            if (mProfileMaximumTimeOff != 0) {
                writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline);
            }
            if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) {
                writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage);
            }
            if (mAlwaysOnVpnLockdown) {
                writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown);
            }
        }
        void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1686,6 +1696,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
                    mProfileOffDeadline =
                            Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
                } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) {
                    mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE);
                } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
                    mAlwaysOnVpnLockdown = Boolean.parseBoolean(
                            parser.getAttributeValue(null, ATTR_VALUE));
                } else {
                    Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                    XmlUtils.skipCurrentTag(parser);
@@ -1918,6 +1933,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                pw.println(mProfileMaximumTimeOff);
            pw.print("mProfileOffDeadline=");
                pw.println(mProfileOffDeadline);
            pw.print("mAlwaysOnVpnPackage=");
            pw.println(mAlwaysOnVpnPackage);
            pw.print("mAlwaysOnVpnLockdown=");
            pw.println(mAlwaysOnVpnLockdown);
        }
    }
@@ -6775,10 +6794,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
     * @throws UnsupportedOperationException if the package does not support being set as always-on.
     */
    @Override
    public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown,
    public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown,
            List<String> lockdownWhitelist)
            throws SecurityException {
        enforceProfileOrDeviceOwner(admin);
        enforceProfileOrDeviceOwner(who);
        final int userId = mInjector.userHandleGetCallingUserId();
        mInjector.binderWithCleanCallingIdentity(() -> {
@@ -6804,12 +6823,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            }
            DevicePolicyEventLogger
                    .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE)
                    .setAdmin(admin)
                    .setAdmin(who)
                    .setStrings(vpnPackage)
                    .setBoolean(lockdown)
                    .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0)
                    .write();
        });
        synchronized (getLockObject()) {
            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
            if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage)
                    || lockdown != admin.mAlwaysOnVpnLockdown) {
                admin.mAlwaysOnVpnPackage = vpnPackage;
                admin.mAlwaysOnVpnLockdown = lockdown;
                saveSettingsLocked(userId);
            }
        }
        return true;
    }
@@ -6822,6 +6851,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                () -> mInjector.getConnectivityManager().getAlwaysOnVpnPackageForUser(userId));
    }
    @Override
    public String getAlwaysOnVpnPackageForUser(int userHandle) {
        enforceSystemCaller("getAlwaysOnVpnPackageForUser");
        synchronized (getLockObject()) {
            ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
            return admin != null ? admin.mAlwaysOnVpnPackage : null;
        }
    }
    @Override
    public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
        enforceProfileOrDeviceOwner(admin);
@@ -6831,6 +6869,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                () -> mInjector.getConnectivityManager().isVpnLockdownEnabled(userId));
    }
    @Override
    public boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle) {
        enforceSystemCaller("isAlwaysOnVpnLockdownEnabledForUser");
        synchronized (getLockObject()) {
            ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
            return admin != null ? admin.mAlwaysOnVpnLockdown : null;
        }
    }
    @Override
    public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin)
            throws SecurityException {
@@ -8977,6 +9024,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        return null;
    }
    /**
     * Returns the ActiveAdmin associated wit the PO or DO on the given user.
     * @param userHandle
     * @return
     */
    private @Nullable ActiveAdmin getDeviceOrProfileOwnerAdminLocked(int userHandle) {
        ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
        if (admin == null && getDeviceOwnerUserId() == userHandle) {
            admin = getDeviceOwnerAdminLocked();
        }
        return admin;
    }
    @GuardedBy("getLockObject()")
    ActiveAdmin getProfileOwnerOfOrganizationOwnedDeviceLocked(int userHandle) {
        return mInjector.binderWithCleanCallingIdentity(() -> {