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

Commit 0fa9987b authored by Robin Lee's avatar Robin Lee Committed by Android (Google) Code Review
Browse files

Merge "SecurityController: track VPN for all users"

parents 954863ab 9cb1d5f6
Loading
Loading
Loading
Loading
+11 −23
Original line number Diff line number Diff line
@@ -909,37 +909,25 @@
    <string name="disconnect_vpn">Disconnect VPN</string>

    <!-- Monitoring dialog device owner body text [CHAR LIMIT=400] -->
    <string name="monitoring_description_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>

    <!-- Monitoring dialog non-legacy VPN text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn">You gave \"<xliff:g id="application">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and secure websites.</string>

    <!-- Monitoring dialog legacy VPN text [CHAR LIMIT=400] -->
    <string name="monitoring_description_legacy_vpn">You\'re connected to a VPN (\"<xliff:g id="application">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your device and network activity including emails, apps, and secure websites.</string>

    <!-- Monitoring dialog non-legacy VPN with device owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="application">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too.</string>

    <!-- Monitoring dialog legacy VPN with device owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_legacy_vpn_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you\'re connected to a VPN (\"<xliff:g id="application">%2$s</xliff:g>\"). Your VPN service provider can monitor network activity too.</string>
    <string name="monitoring_description_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information. For more information, contact your administrator.</string>

    <!-- Monitoring dialog profile owner body text [CHAR LIMIT=400] -->
    <string name="monitoring_description_profile_owned">This profile is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
    <string name="monitoring_description_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>

    <!-- Monitoring dialog device and profile owner body text [CHAR LIMIT=400] -->
    <string name="monitoring_description_device_and_profile_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\nYour profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
    <string name="monitoring_description_device_and_profile_owned">Your device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>.\nYour work profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>.\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>

    <!-- Monitoring dialog non-legacy VPN with profile owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn_profile_owned">This profile is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="application">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too.</string>
    <!-- Monitoring dialog VPN text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and secure websites.</string>

    <!-- Monitoring dialog legacy VPN with profile owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_legacy_vpn_profile_owned">This profile is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you\'re connected to a VPN (\"<xliff:g id="application">%2$s</xliff:g>\"). Your VPN service provider can monitor network activity too.</string>
    <!-- Monitoring dialog VPN with device owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nYou\'re connected to a VPN, which can monitor your network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>

    <!-- Monitoring dialog non-legacy VPN with device and profile owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn_device_and_profile_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\nYour profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="application">%3$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too.</string>
    <!-- Monitoring dialog VPN with profile owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>

    <!-- Monitoring dialog legacy VPN with device and profile owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_legacy_vpn_device_and_profile_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\nYour profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you\'re connected to a VPN (\"<xliff:g id="application">%3$s</xliff:g>\"). Your VPN service provider can monitor network activity too.</string>
    <!-- Monitoring dialog VPN with device and profile owner text [CHAR LIMIT=400] -->
    <string name="monitoring_description_vpn_device_and_profile_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\nYour work profile is managed by:\n<xliff:g id="organization">%2$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your personal network activity</string>

    <!-- Indication on the keyguard that appears when the user disables trust agents until the next time they unlock manually. [CHAR LIMIT=NONE] -->
    <string name="keyguard_indication_trust_disabled">Device will stay locked until you manually unlock</string>
+34 −62
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@ package com.android.systemui.qs;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -38,6 +40,8 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    protected static final String TAG = "QSFooter";
    protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";

    private final View mRootView;
    private final TextView mFooterText;
    private final ImageView mFooterIcon;
@@ -128,50 +132,42 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (which == DialogInterface.BUTTON_NEGATIVE) {
            mSecurityController.disconnectFromVpn();
            final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
            mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
        }
    }

    private void createDialog() {
        boolean hasDeviceOwner = mSecurityController.hasDeviceOwner();
        boolean hasProfile = mSecurityController.hasProfileOwner();
        boolean hasVpn = mSecurityController.isVpnEnabled();

        mDialog = new SystemUIDialog(mContext);
        mDialog.setTitle(getTitle());
        mDialog.setMessage(getMessage());
        mDialog.setTitle(getTitle(hasDeviceOwner, hasProfile));
        mDialog.setMessage(getMessage(hasDeviceOwner, hasProfile, hasVpn));
        mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
        if (mSecurityController.isVpnEnabled()) {
        if (hasVpn) {
            mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this);
        }
        mDialog.show();
    }

    private String getNegativeButton() {
        if (mSecurityController.isLegacyVpn()) {
            return mContext.getString(R.string.disconnect_vpn);
        } else {
            return mContext.getString(R.string.disable_vpn);
        }
        return mContext.getString(R.string.status_bar_settings_settings_button);
    }

    private String getPositiveButton() {
        return mContext.getString(R.string.quick_settings_done);
    }

    private String getMessage() {
        if (mSecurityController.hasDeviceOwner()) {
            if (mSecurityController.hasProfileOwner()) {
                if (mSecurityController.isVpnEnabled()) {
                    if (mSecurityController.isLegacyVpn()) {
                        return mContext.getString(
                                R.string.monitoring_description_legacy_vpn_device_and_profile_owned,
                                mSecurityController.getDeviceOwnerName(),
                                mSecurityController.getProfileOwnerName(),
                                mSecurityController.getLegacyVpnName());
                    } else {
    private String getMessage(boolean hasDeviceOwner, boolean hasProfile, boolean hasVpn) {
        if (hasDeviceOwner) {
            if (hasProfile) {
                if (hasVpn) {
                    return mContext.getString(
                            R.string.monitoring_description_vpn_device_and_profile_owned,
                            mSecurityController.getDeviceOwnerName(),
                                mSecurityController.getProfileOwnerName(),
                                mSecurityController.getVpnApp());
                    }
                            mSecurityController.getProfileOwnerName());
                } else {
                    return mContext.getString(
                            R.string.monitoring_description_device_and_profile_owned,
@@ -179,57 +175,33 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
                            mSecurityController.getProfileOwnerName());
                }
            } else {
                if (mSecurityController.isVpnEnabled()) {
                    if (mSecurityController.isLegacyVpn()) {
                        return mContext.getString(
                                R.string.monitoring_description_legacy_vpn_device_owned,
                                mSecurityController.getDeviceOwnerName(),
                                mSecurityController.getLegacyVpnName());
                    } else {
                if (hasVpn) {
                    return mContext.getString(R.string.monitoring_description_vpn_device_owned,
                                mSecurityController.getDeviceOwnerName(),
                                mSecurityController.getVpnApp());
                    }
                            mSecurityController.getDeviceOwnerName());
                } else {
                    return mContext.getString(R.string.monitoring_description_device_owned,
                            mSecurityController.getDeviceOwnerName());
                }
            }
        } else if (mSecurityController.hasProfileOwner()) {
            if (mSecurityController.isVpnEnabled()) {
                if (mSecurityController.isLegacyVpn()) {
                    return mContext.getString(
                            R.string.monitoring_description_legacy_vpn_profile_owned,
                            mSecurityController.getProfileOwnerName(),
                            mSecurityController.getLegacyVpnName());
                } else {
        } else if (hasProfile) {
            if (hasVpn) {
                return mContext.getString(
                        R.string.monitoring_description_vpn_profile_owned,
                            mSecurityController.getProfileOwnerName(),
                            mSecurityController.getVpnApp());
                }
                        mSecurityController.getProfileOwnerName());
            } else {
                return mContext.getString(
                        R.string.monitoring_description_profile_owned,
                        mSecurityController.getProfileOwnerName());
            }
        } else {
            if (mSecurityController.isLegacyVpn()) {
                return mContext.getString(R.string.monitoring_description_legacy_vpn,
                        mSecurityController.getLegacyVpnName());

            } else {
                return mContext.getString(R.string.monitoring_description_vpn,
                        mSecurityController.getVpnApp());
            }
            return mContext.getString(R.string.monitoring_description_vpn);
        }
    }

    private int getTitle() {
        if (mSecurityController.hasDeviceOwner()) {
    private int getTitle(boolean hasDeviceOwner, boolean hasProfile) {
        if (hasDeviceOwner) {
            return R.string.monitoring_title_device_owned;
        }
        if (mSecurityController.hasProfileOwner()) {
        } else if (hasProfile) {
            return R.string.monitoring_title_profile_owned;
        }
        return R.string.monitoring_title;
+0 −4
Original line number Diff line number Diff line
@@ -22,10 +22,6 @@ public interface SecurityController {
    String getDeviceOwnerName();
    String getProfileOwnerName();
    boolean isVpnEnabled();
    String getVpnApp();
    boolean isLegacyVpn();
    String getLegacyVpnName();
    void disconnectFromVpn();
    void onUserSwitched(int newUserId);

    void addCallback(SecurityControllerCallback callback);
+46 −70
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
@@ -27,10 +28,14 @@ import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;

import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -50,15 +55,13 @@ public class SecurityControllerImpl implements SecurityController {

    private final Context mContext;
    private final ConnectivityManager mConnectivityManager;
    private final IConnectivityManager mConnectivityService = IConnectivityManager.Stub.asInterface(
                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
    private final IConnectivityManager mConnectivityManagerService;
    private final DevicePolicyManager mDevicePolicyManager;
    private final UserManager mUserManager;
    private final ArrayList<SecurityControllerCallback> mCallbacks
            = new ArrayList<SecurityControllerCallback>();

    private VpnConfig mVpnConfig;
    private String mVpnName;
    private int mCurrentVpnNetworkId = NO_NETWORK;
    private SparseArray<Boolean> mCurrentVpnUsers = new SparseArray<>();
    private int mCurrentUserId;

    public SecurityControllerImpl(Context context) {
@@ -67,6 +70,10 @@ public class SecurityControllerImpl implements SecurityController {
                context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        mConnectivityManager = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        mConnectivityManagerService = IConnectivityManager.Stub.asInterface(
                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
        mUserManager = (UserManager)
                context.getSystemService(Context.USER_SERVICE);

        // TODO: re-register network callback on user change.
        mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
@@ -75,9 +82,7 @@ public class SecurityControllerImpl implements SecurityController {

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("SecurityController state:");
        pw.print("  mCurrentVpnNetworkId="); pw.println(mCurrentVpnNetworkId);
        pw.print("  mVpnConfig="); pw.println(mVpnConfig);
        pw.print("  mVpnName="); pw.println(mVpnName);
        pw.print("  mCurrentVpnUsers=" + mCurrentVpnUsers);
    }

    @Override
@@ -85,57 +90,34 @@ public class SecurityControllerImpl implements SecurityController {
        return !TextUtils.isEmpty(mDevicePolicyManager.getDeviceOwner());
    }

    @Override
    public boolean hasProfileOwner() {
        return !TextUtils.isEmpty(mDevicePolicyManager.getProfileOwnerNameAsUser(mCurrentUserId));
    }

    @Override
    public String getDeviceOwnerName() {
        return mDevicePolicyManager.getDeviceOwnerName();
    }

    @Override
    public String getProfileOwnerName() {
        return mDevicePolicyManager.getProfileOwnerNameAsUser(mCurrentUserId);
    public boolean hasProfileOwner() {
        boolean result = false;
        for (UserInfo profile : mUserManager.getProfiles(mCurrentUserId)) {
            result |= (mDevicePolicyManager.getProfileOwnerAsUser(profile.id) != null);
        }


    @Override
    public boolean isVpnEnabled() {
        return mCurrentVpnNetworkId != NO_NETWORK;
        return result;
    }

    @Override
    public boolean isLegacyVpn() {
        return mVpnConfig.legacy;
    public String getProfileOwnerName() {
        for (UserInfo profile : mUserManager.getProfiles(mCurrentUserId)) {
            String name = mDevicePolicyManager.getProfileOwnerNameAsUser(profile.id);
            if (name != null) {
                return name;
            }

    @Override
    public String getVpnApp() {
        return mVpnName;
        }

    @Override
    public String getLegacyVpnName() {
        return mVpnConfig.session;
        return null;
    }

    @Override
    public void disconnectFromVpn() {
        try {
            if (isLegacyVpn()) {
                mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
            } else {
                // Prevent this app from initiating VPN connections in the future without user
                // intervention.
                mConnectivityService.setVpnPackageAuthorization(false);

                mConnectivityService.prepareVpn(mVpnConfig.user, VpnConfig.LEGACY_VPN);
            }
        } catch (Exception e) {
            Log.e(TAG, "Unable to disconnect from VPN", e);
        }
    public boolean isVpnEnabled() {
        return mCurrentVpnUsers.get(mCurrentUserId) != null;
    }

    @Override
@@ -158,14 +140,6 @@ public class SecurityControllerImpl implements SecurityController {
        fireCallbacks();
    }

    private void setCurrentNetid(int netId) {
        if (netId != mCurrentVpnNetworkId) {
            mCurrentVpnNetworkId = netId;
            updateState();
            fireCallbacks();
        }
    }

    private void fireCallbacks() {
        for (SecurityControllerCallback callback : mCallbacks) {
            callback.onStateChanged();
@@ -173,27 +147,30 @@ public class SecurityControllerImpl implements SecurityController {
    }

    private void updateState() {
        // Find all users with an active VPN
        SparseArray<Boolean> vpnUsers = new SparseArray<>();
        try {
            mVpnConfig = mConnectivityService.getVpnConfig();
            for (VpnInfo vpn : mConnectivityManagerService.getAllVpnInfo()) {
                UserInfo user = mUserManager.getUserInfo(UserHandle.getUserId(vpn.ownerUid));
                int groupId = (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID ?
                        user.profileGroupId : user.id);

            if (mVpnConfig != null && !mVpnConfig.legacy) {
                mVpnName = VpnConfig.getVpnLabel(mContext, mVpnConfig.user).toString();
                vpnUsers.put(groupId, Boolean.TRUE);
            }
        } catch (RemoteException | NameNotFoundException e) {
            Log.w(TAG, "Unable to get current VPN", e);
        } catch (RemoteException rme) {
            // Roll back to previous state
            Log.e(TAG, "Unable to list active VPNs", rme);
            return;
        }
        mCurrentVpnUsers = vpnUsers;
    }

    private final NetworkCallback mNetworkCallback = new NetworkCallback() {
        @Override
        public void onAvailable(Network network) {
            NetworkCapabilities networkCapabilities =
                    mConnectivityManager.getNetworkCapabilities(network);
            if (DEBUG) Log.d(TAG, "onAvailable " + network.netId + " : " + networkCapabilities);
            if (networkCapabilities != null &&
                    networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
                setCurrentNetid(network.netId);
            }
            if (DEBUG) Log.d(TAG, "onAvailable " + network.netId);
            updateState();
            fireCallbacks();
        };

        // TODO Find another way to receive VPN lost.  This may be delayed depending on
@@ -201,9 +178,8 @@ public class SecurityControllerImpl implements SecurityController {
        @Override
        public void onLost(Network network) {
            if (DEBUG) Log.d(TAG, "onLost " + network.netId);
            if (mCurrentVpnNetworkId == network.netId) {
                setCurrentNetid(NO_NETWORK);
            }
            updateState();
            fireCallbacks();
        };
    };