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

Commit 35717954 authored by Lucas Lin's avatar Lucas Lin Committed by Gerrit Code Review
Browse files

Merge changes from topic "VPN_APPOPS"

* changes:
  Add startOp and finishOp to track the behavior of VPN app
  Add new appOps to track the behavior of VPN app
parents e2c0dcfe 33e0d8cb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -475,6 +475,8 @@ package android.app {
    field public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = "android:auto_revoke_permissions_if_unused";
    field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
    field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
    field public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager";
    field public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service";
    field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
    field public static final String OPSTR_GPS = "android:gps";
    field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+48 −2
Original line number Diff line number Diff line
@@ -1313,9 +1313,23 @@ public class AppOpsManager {
    public static final int OP_RECORD_INCOMING_PHONE_AUDIO =
            AppProtoEnums.APP_OP_RECORD_INCOMING_PHONE_AUDIO;

    /**
     * VPN app establishes a connection through the VpnService API.
     *
     * @hide
     */
    public static final int OP_ESTABLISH_VPN_SERVICE = AppProtoEnums.APP_OP_ESTABLISH_VPN_SERVICE;

    /**
     * VPN app establishes a connection through the VpnManager API.
     *
     * @hide
     */
    public static final int OP_ESTABLISH_VPN_MANAGER = AppProtoEnums.APP_OP_ESTABLISH_VPN_MANAGER;

    /** @hide */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public static final int _NUM_OP = 117;
    public static final int _NUM_OP = 119;

    /** Access to coarse location information. */
    public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1754,6 +1768,22 @@ public class AppOpsManager {
    public static final String OPSTR_RECORD_INCOMING_PHONE_AUDIO =
            "android:record_incoming_phone_audio";

    /**
     * VPN app establishes a connection through the VpnService API.
     *
     * @hide
     */
    @SystemApi
    public static final String OPSTR_ESTABLISH_VPN_SERVICE = "android:establish_vpn_service";

    /**
     * VPN app establishes a connection through the VpnManager API.
     *
     * @hide
     */
    @SystemApi
    public static final String OPSTR_ESTABLISH_VPN_MANAGER = "android:establish_vpn_manager";

    /** {@link #sAppOpsToNote} not initialized yet for this op */
    private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
    /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1970,6 +2000,8 @@ public class AppOpsManager {
            OP_BLUETOOTH_ADVERTISE,             // OP_BLUETOOTH_ADVERTISE
            OP_RECORD_INCOMING_PHONE_AUDIO,     // OP_RECORD_INCOMING_PHONE_AUDIO
            OP_NEARBY_WIFI_DEVICES,             // OP_NEARBY_WIFI_DEVICES
            OP_ESTABLISH_VPN_SERVICE,           // OP_ESTABLISH_VPN_SERVICE
            OP_ESTABLISH_VPN_MANAGER,           // OP_ESTABLISH_VPN_MANAGER
    };

    /**
@@ -2093,6 +2125,8 @@ public class AppOpsManager {
            OPSTR_BLUETOOTH_ADVERTISE,
            OPSTR_RECORD_INCOMING_PHONE_AUDIO,
            OPSTR_NEARBY_WIFI_DEVICES,
            OPSTR_ESTABLISH_VPN_SERVICE,
            OPSTR_ESTABLISH_VPN_MANAGER,
    };

    /**
@@ -2216,7 +2250,9 @@ public class AppOpsManager {
            "ACTIVITY_RECOGNITION_SOURCE",
            "BLUETOOTH_ADVERTISE",
            "RECORD_INCOMING_PHONE_AUDIO",
            "NEARBY_WIFI_DEVICES"
            "NEARBY_WIFI_DEVICES",
            "ESTABLISH_VPN_SERVICE",
            "ESTABLISH_VPN_MANAGER",
    };

    /**
@@ -2342,6 +2378,8 @@ public class AppOpsManager {
            Manifest.permission.BLUETOOTH_ADVERTISE,
            null, // no permission for OP_RECORD_INCOMING_PHONE_AUDIO,
            Manifest.permission.NEARBY_WIFI_DEVICES,
            null, // no permission for OP_ESTABLISH_VPN_SERVICE
            null, // no permission for OP_ESTABLISH_VPN_MANAGER
    };

    /**
@@ -2467,6 +2505,8 @@ public class AppOpsManager {
            null, // BLUETOOTH_ADVERTISE
            null, // RECORD_INCOMING_PHONE_AUDIO
            null, // NEARBY_WIFI_DEVICES
            null, // ESTABLISH_VPN_SERVICE
            null, // ESTABLISH_VPN_MANAGER
    };

    /**
@@ -2591,6 +2631,8 @@ public class AppOpsManager {
            null, // BLUETOOTH_ADVERTISE
            null, // RECORD_INCOMING_PHONE_AUDIO
            null, // NEARBY_WIFI_DEVICES
            null, // ESTABLISH_VPN_SERVICE
            null, // ESTABLISH_VPN_MANAGER
    };

    /**
@@ -2714,6 +2756,8 @@ public class AppOpsManager {
            AppOpsManager.MODE_ALLOWED, // BLUETOOTH_ADVERTISE
            AppOpsManager.MODE_ALLOWED, // RECORD_INCOMING_PHONE_AUDIO
            AppOpsManager.MODE_ALLOWED, // NEARBY_WIFI_DEVICES
            AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_SERVICE
            AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_MANAGER
    };

    /**
@@ -2841,6 +2885,8 @@ public class AppOpsManager {
            false, // BLUETOOTH_ADVERTISE
            false, // RECORD_INCOMING_PHONE_AUDIO
            false, // NEARBY_WIFI_DEVICES
            false, // OP_ESTABLISH_VPN_SERVICE
            false, // OP_ESTABLISH_VPN_MANAGER
    };

    /**
+74 −14
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ import com.android.server.net.BaseNetworkObserver;
import libcore.io.IoUtils;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -195,6 +196,7 @@ public class Vpn {

    private final Context mContext;
    private final ConnectivityManager mConnectivityManager;
    private final AppOpsManager mAppOpsManager;
    // The context is for specific user which is created from mUserId
    private final Context mUserIdContext;
    @VisibleForTesting final Dependencies mDeps;
@@ -407,6 +409,46 @@ public class Vpn {
        public boolean isInterfacePresent(final Vpn vpn, final String iface) {
            return vpn.jniCheck(iface) != 0;
        }

        /**
         * @see ParcelFileDescriptor#adoptFd(int)
         */
        public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) {
            return ParcelFileDescriptor.adoptFd(jniCreate(vpn, mtu));
        }

        /**
         * Call native method to create the VPN interface and return the FileDescriptor of /dev/tun.
         */
        public int jniCreate(Vpn vpn, int mtu) {
            return vpn.jniCreate(mtu);
        }

        /**
         * Call native method to get the interface name of VPN.
         */
        public String jniGetName(Vpn vpn, int fd) {
            return vpn.jniGetName(fd);
        }

        /**
         * Call native method to set the VPN addresses and return the number of addresses.
         */
        public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) {
            return vpn.jniSetAddresses(interfaze, addresses);
        }

        /**
         * @see IoUtils#setBlocking(FileDescriptor, boolean)
         */
        public void setBlocking(FileDescriptor fd, boolean blocking) {
            try {
                IoUtils.setBlocking(fd, blocking);
            } catch (IOException e) {
                throw new IllegalStateException(
                        "Cannot set tunnel's fd as blocking=" + blocking, e);
            }
        }
    }

    public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
@@ -431,6 +473,7 @@ public class Vpn {
        mVpnProfileStore = vpnProfileStore;
        mContext = context;
        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
        mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
        mDeps = deps;
        mNms = netService;
@@ -826,7 +869,6 @@ public class Vpn {
            VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage);
            if (profile != null) {
                startVpnProfilePrivileged(profile, alwaysOnPackage);

                // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was
                // correctly parsed, and the VPN has started running in a different thread. The only
                // other possibility is that the above call threw an exception, which will be
@@ -974,9 +1016,15 @@ public class Vpn {
                } catch (Exception e) {
                    // ignore
                }
                mAppOpsManager.finishOp(
                        AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null);
                mContext.unbindService(mConnection);
                cleanupVpnStateLocked();
            } else if (mVpnRunner != null) {
                if (!VpnConfig.LEGACY_VPN.equals(mPackage)) {
                    mAppOpsManager.finishOp(
                            AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null);
                }
                // cleanupVpnStateLocked() is called from mVpnRunner.exit()
                mVpnRunner.exit();
            }
@@ -1041,10 +1089,8 @@ public class Vpn {
                    return false;
            }

            final AppOpsManager appOpMgr =
                    (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
            for (final String appOpStr : toChange) {
                appOpMgr.setMode(
                mAppOpsManager.setMode(
                        appOpStr,
                        uid,
                        packageName,
@@ -1366,9 +1412,9 @@ public class Vpn {
        Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids();

        // Configure the interface. Abort if any of these steps fails.
        ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
        final ParcelFileDescriptor tun = mDeps.adoptFd(this, config.mtu);
        try {
            String interfaze = jniGetName(tun.getFd());
            final String interfaze = mDeps.jniGetName(this, tun.getFd());

            // TEMP use the old jni calls until there is support for netd address setting
            StringBuilder builder = new StringBuilder();
@@ -1376,7 +1422,7 @@ public class Vpn {
                builder.append(" ");
                builder.append(address);
            }
            if (jniSetAddresses(interfaze, builder.toString()) < 1) {
            if (mDeps.jniSetAddresses(this, interfaze, builder.toString()) < 1) {
                throw new IllegalArgumentException("At least one address must be specified");
            }
            Connection connection = new Connection();
@@ -1422,11 +1468,11 @@ public class Vpn {
                jniReset(oldInterface);
            }

            try {
                IoUtils.setBlocking(tun.getFileDescriptor(), config.blocking);
            } catch (IOException e) {
                throw new IllegalStateException(
                        "Cannot set tunnel's fd as blocking=" + config.blocking, e);
            mDeps.setBlocking(tun.getFileDescriptor(), config.blocking);
            // Record that the VPN connection is established by an app which uses VpnService API.
            if (oldNetworkAgent != mNetworkAgent) {
                mAppOpsManager.startOp(
                        AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null, null);
            }
        } catch (RuntimeException e) {
            IoUtils.closeQuietly(tun);
@@ -1781,9 +1827,17 @@ public class Vpn {
            synchronized (Vpn.this) {
                if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
                    if (mConnection != null) {
                        mAppOpsManager.finishOp(
                                AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage,
                                null);
                        mContext.unbindService(mConnection);
                        cleanupVpnStateLocked();
                    } else if (mVpnRunner != null) {
                        if (!VpnConfig.LEGACY_VPN.equals(mPackage)) {
                            mAppOpsManager.finishOp(
                                    AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage,
                                    null);
                        }
                        // cleanupVpnStateLocked() is called from mVpnRunner.exit()
                        mVpnRunner.exit();
                    }
@@ -3254,8 +3308,7 @@ public class Vpn {
     *
     * @param packageName the package name of the app provisioning this profile
     */
    public synchronized void startVpnProfile(
            @NonNull String packageName) {
    public synchronized void startVpnProfile(@NonNull String packageName) {
        requireNonNull(packageName, "No package name provided");

        enforceNotRestrictedUser();
@@ -3318,6 +3371,13 @@ public class Vpn {
                    Log.d(TAG, "Unknown VPN profile type: " + profile.type);
                    break;
            }

            // Record that the VPN connection is established by an app which uses VpnManager API.
            if (!VpnConfig.LEGACY_VPN.equals(packageName)) {
                mAppOpsManager.startOp(
                        AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null,
                        null);
            }
        } catch (GeneralSecurityException e) {
            // Reset mConfig
            mConfig = null;