summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Benedict Wong <benedictwong@google.com> 2020-02-04 21:04:01 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-02-04 21:04:01 +0000
commit70ee4c46a66078e4277c6d2415d23c919a59d17c (patch)
tree61730336c63c3891af7bef13b0e26e9521a876ea
parentfb961bf0bd4364a9c0caa616e0e9b88997a4bb13 (diff)
parent418017e5f9a320b845cf9722fb4aa03d9710b091 (diff)
Merge "Add separate user consent for Platform VPNs"
-rw-r--r--core/java/android/net/IConnectivityManager.aidl2
-rw-r--r--core/java/android/net/VpnManager.java17
-rw-r--r--core/java/android/net/VpnService.java2
-rw-r--r--core/res/res/values/config.xml6
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--packages/VpnDialogs/AndroidManifest.xml7
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java13
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/PlatformVpnConfirmDialog.java29
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java27
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java77
-rw-r--r--tests/net/java/android/net/VpnManagerTest.java11
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java50
12 files changed, 200 insertions, 42 deletions
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 6baa3832403f..1089a197ff59 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -117,7 +117,7 @@ interface IConnectivityManager
boolean prepareVpn(String oldPackage, String newPackage, int userId);
- void setVpnPackageAuthorization(String packageName, int userId, boolean authorized);
+ void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
ParcelFileDescriptor establishVpn(in VpnConfig config);
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index e60cc81bf9d2..f19ba0f5ef51 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -18,6 +18,7 @@ package android.net;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
@@ -30,6 +31,8 @@ import android.os.RemoteException;
import com.android.internal.net.VpnProfile;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.security.GeneralSecurityException;
/**
@@ -47,6 +50,18 @@ import java.security.GeneralSecurityException;
* @see Ikev2VpnProfile
*/
public class VpnManager {
+ /** Type representing a lack of VPN @hide */
+ public static final int TYPE_VPN_NONE = -1;
+ /** VPN service type code @hide */
+ public static final int TYPE_VPN_SERVICE = 1;
+ /** Platform VPN type code @hide */
+ public static final int TYPE_VPN_PLATFORM = 2;
+
+ /** @hide */
+ @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VpnType {}
+
@NonNull private final Context mContext;
@NonNull private final IConnectivityManager mService;
@@ -54,7 +69,7 @@ public class VpnManager {
final Intent intent = new Intent();
final ComponentName componentName = ComponentName.unflattenFromString(
Resources.getSystem().getString(
- com.android.internal.R.string.config_customVpnConfirmDialogComponent));
+ com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
intent.setComponent(componentName);
return intent;
}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 4b804b097d59..63e510733907 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -234,7 +234,7 @@ public class VpnService extends Service {
if (!cm.prepareVpn(packageName, null, userId)) {
cm.prepareVpn(null, packageName, userId);
}
- cm.setVpnPackageAuthorization(packageName, userId, true);
+ cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
} catch (RemoteException e) {
// ignore
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d240c9c18702..3d7b1e18be7b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2565,7 +2565,11 @@
<string name="config_usbResolverActivity" translatable="false"
>com.android.systemui/com.android.systemui.usb.UsbResolverActivity</string>
- <!-- Name of the dialog that is used to request the user's consent to VPN connection -->
+ <!-- Name of the dialog that is used to request the user's consent for a Platform VPN -->
+ <string name="config_platformVpnConfirmDialogComponent" translatable="false"
+ >com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog</string>
+
+ <!-- Name of the dialog that is used to request the user's consent for a VpnService VPN -->
<string name="config_customVpnConfirmDialogComponent" translatable="false"
>com.android.vpndialogs/com.android.vpndialogs.ConfirmDialog</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f47da62654e2..36296a850dcb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2143,6 +2143,7 @@
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationSecondaryUserComponent" />
<java-symbol type="string" name="config_customVpnConfirmDialogComponent" />
<java-symbol type="string" name="config_customVpnAlwaysOnDisconnectedDialogComponent" />
+ <java-symbol type="string" name="config_platformVpnConfirmDialogComponent" />
<java-symbol type="string" name="config_carrierAppInstallDialogComponent" />
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index e4de6259e07d..693ca52b4ed1 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -34,6 +34,13 @@
</intent-filter>
</activity>
+ <activity android:name=".PlatformVpnConfirmDialog"
+ android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"
+ android:noHistory="true"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ </activity>
+
<activity android:name=".ManageDialog"
android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"
android:noHistory="true"
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index 48adb9ba3f63..e66f2cc17a7f 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -23,6 +23,7 @@ import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.IConnectivityManager;
+import android.net.VpnManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -43,10 +44,20 @@ public class ConfirmDialog extends AlertActivity
implements DialogInterface.OnClickListener, ImageGetter {
private static final String TAG = "VpnConfirm";
+ @VpnManager.VpnType private final int mVpnType;
+
private String mPackage;
private IConnectivityManager mService;
+ public ConfirmDialog() {
+ this(VpnManager.TYPE_VPN_SERVICE);
+ }
+
+ public ConfirmDialog(@VpnManager.VpnType int vpnType) {
+ mVpnType = vpnType;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -138,7 +149,7 @@ public class ConfirmDialog extends AlertActivity
if (mService.prepareVpn(null, mPackage, UserHandle.myUserId())) {
// Authorize this app to initiate VPN connections in the future without user
// intervention.
- mService.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), true);
+ mService.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), mVpnType);
setResult(RESULT_OK);
}
} catch (Exception e) {
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/PlatformVpnConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/PlatformVpnConfirmDialog.java
new file mode 100644
index 000000000000..e2e297caad14
--- /dev/null
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/PlatformVpnConfirmDialog.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 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 com.android.vpndialogs;
+
+import android.net.VpnManager;
+
+/**
+ * PlatformVpnConfirmDialog is a minimal subclass for requesting user consent for platform VPN
+ * profiles.
+ */
+public class PlatformVpnConfirmDialog extends ConfirmDialog {
+ public PlatformVpnConfirmDialog() {
+ super(VpnManager.TYPE_VPN_PLATFORM);
+ }
+}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3877e9a71f26..2968a816835d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -109,6 +109,7 @@ import android.net.SocketKeepalive;
import android.net.TetheringManager;
import android.net.UidRange;
import android.net.Uri;
+import android.net.VpnManager;
import android.net.VpnService;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
@@ -4317,7 +4318,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
throwIfLockdownEnabled();
Vpn vpn = mVpns.get(userId);
if (vpn != null) {
- return vpn.prepare(oldPackage, newPackage, false);
+ return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
} else {
return false;
}
@@ -4325,26 +4326,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
- * Set whether the VPN package has the ability to launch VPNs without user intervention.
- * This method is used by system-privileged apps.
- * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
- * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ * Set whether the VPN package has the ability to launch VPNs without user intervention. This
+ * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
+ * class. If the caller is not {@code userId}, {@link
+ * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
*
* @param packageName The package for which authorization state should change.
* @param userId User for whom {@code packageName} is installed.
* @param authorized {@code true} if this app should be able to start a VPN connection without
- * explicit user approval, {@code false} if not.
- *
+ * explicit user approval, {@code false} if not.
+ * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
+ * permissions should be granted. When unauthorizing an app, {@link
+ * VpnManager.TYPE_VPN_NONE} should be used.
* @hide
*/
@Override
- public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) {
+ public void setVpnPackageAuthorization(
+ String packageName, int userId, @VpnManager.VpnType int vpnType) {
enforceCrossUserPermission(userId);
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn != null) {
- vpn.setPackageAuthorization(packageName, authorized);
+ vpn.setPackageAuthorization(packageName, vpnType);
}
}
}
@@ -7230,7 +7234,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
if (alwaysOnPackage != null) {
setAlwaysOnVpnPackage(userId, null, false, null);
- setVpnPackageAuthorization(alwaysOnPackage, userId, false);
+ setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
}
// Turn Always-on VPN off
@@ -7253,7 +7257,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
// Prevent this app (packagename = vpnConfig.user) from initiating
// VPN connections in the future without user intervention.
- setVpnPackageAuthorization(vpnConfig.user, userId, false);
+ setVpnPackageAuthorization(
+ vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 03795597f47a..89af5b58ff72 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -62,6 +62,7 @@ import android.net.NetworkInfo.DetailedState;
import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.UidRange;
+import android.net.VpnManager;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
@@ -519,8 +520,11 @@ public class Vpn {
}
if (packageName != null) {
- // Pre-authorize new always-on VPN package.
- if (!setPackageAuthorization(packageName, true)) {
+ // TODO: Give the minimum permission possible; if there is a Platform VPN profile, only
+ // grant ACTIVATE_PLATFORM_VPN.
+ // Pre-authorize new always-on VPN package. Grant the full ACTIVATE_VPN appop, allowing
+ // both VpnService and Platform VPNs.
+ if (!setPackageAuthorization(packageName, VpnManager.TYPE_VPN_SERVICE)) {
return false;
}
mAlwaysOn = true;
@@ -691,13 +695,12 @@ public class Vpn {
*
* @param oldPackage The package name of the old VPN application
* @param newPackage The package name of the new VPN application
- * @param isPlatformVpn Whether the package being prepared is using a platform VPN profile.
- * Preparing a platform VPN profile requires only the lesser ACTIVATE_PLATFORM_VPN appop.
+ * @param vpnType The type of VPN being prepared. One of {@link VpnManager.VpnType} Preparing a
+ * platform VPN profile requires only the lesser ACTIVATE_PLATFORM_VPN appop.
* @return true if the operation succeeded.
*/
- // TODO: Use an Intdef'd type to represent what kind of VPN the caller is preparing.
public synchronized boolean prepare(
- String oldPackage, String newPackage, boolean isPlatformVpn) {
+ String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) {
if (oldPackage != null) {
// Stop an existing always-on VPN from being dethroned by other apps.
if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) {
@@ -709,13 +712,13 @@ public class Vpn {
// The package doesn't match. We return false (to obtain user consent) unless the
// user has already consented to that VPN package.
if (!oldPackage.equals(VpnConfig.LEGACY_VPN)
- && isVpnPreConsented(mContext, oldPackage, isPlatformVpn)) {
+ && isVpnPreConsented(mContext, oldPackage, vpnType)) {
prepareInternal(oldPackage);
return true;
}
return false;
} else if (!oldPackage.equals(VpnConfig.LEGACY_VPN)
- && !isVpnPreConsented(mContext, oldPackage, isPlatformVpn)) {
+ && !isVpnPreConsented(mContext, oldPackage, vpnType)) {
// Currently prepared VPN is revoked, so unprepare it and return false.
prepareInternal(VpnConfig.LEGACY_VPN);
return false;
@@ -798,25 +801,49 @@ public class Vpn {
}
}
- /**
- * Set whether a package has the ability to launch VPNs without user intervention.
- */
- public boolean setPackageAuthorization(String packageName, boolean authorized) {
+ /** Set whether a package has the ability to launch VPNs without user intervention. */
+ public boolean setPackageAuthorization(String packageName, @VpnManager.VpnType int vpnType) {
// Check if the caller is authorized.
enforceControlPermissionOrInternalCaller();
- int uid = getAppUid(packageName, mUserHandle);
+ final int uid = getAppUid(packageName, mUserHandle);
if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
// Authorization for nonexistent packages (or fake ones) can't be updated.
return false;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
- AppOpsManager appOps =
+ final int[] toChange;
+
+ // Clear all AppOps if the app is being unauthorized.
+ switch (vpnType) {
+ case VpnManager.TYPE_VPN_NONE:
+ toChange = new int[] {
+ AppOpsManager.OP_ACTIVATE_VPN, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN
+ };
+ break;
+ case VpnManager.TYPE_VPN_PLATFORM:
+ toChange = new int[] {AppOpsManager.OP_ACTIVATE_PLATFORM_VPN};
+ break;
+ case VpnManager.TYPE_VPN_SERVICE:
+ toChange = new int[] {AppOpsManager.OP_ACTIVATE_VPN};
+ break;
+ default:
+ Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
+ return false;
+ }
+
+ final AppOpsManager appOpMgr =
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, uid, packageName,
- authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+ for (final int appOp : toChange) {
+ appOpMgr.setMode(
+ appOp,
+ uid,
+ packageName,
+ vpnType == VpnManager.TYPE_VPN_NONE
+ ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED);
+ }
return true;
} catch (Exception e) {
Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e);
@@ -826,11 +853,15 @@ public class Vpn {
return false;
}
- private static boolean isVpnPreConsented(
- Context context, String packageName, boolean isPlatformVpn) {
- return isPlatformVpn
- ? isVpnProfilePreConsented(context, packageName)
- : isVpnServicePreConsented(context, packageName);
+ private static boolean isVpnPreConsented(Context context, String packageName, int vpnType) {
+ switch (vpnType) {
+ case VpnManager.TYPE_VPN_SERVICE:
+ return isVpnServicePreConsented(context, packageName);
+ case VpnManager.TYPE_VPN_PLATFORM:
+ return isVpnProfilePreConsented(context, packageName);
+ default:
+ return false;
+ }
}
private static boolean doesPackageHaveAppop(Context context, String packageName, int appop) {
@@ -2377,7 +2408,7 @@ public class Vpn {
checkNotNull(keyStore, "KeyStore missing");
// Prepare VPN for startup
- if (!prepare(packageName, null /* newPackage */, true /* isPlatformVpn */)) {
+ if (!prepare(packageName, null /* newPackage */, VpnManager.TYPE_VPN_PLATFORM)) {
throw new SecurityException("User consent not granted for package " + packageName);
}
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
index 97551c94e2ae..95a794235a2e 100644
--- a/tests/net/java/android/net/VpnManagerTest.java
+++ b/tests/net/java/android/net/VpnManagerTest.java
@@ -16,6 +16,7 @@
package android.net;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
@@ -24,6 +25,8 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
+import android.content.Intent;
import android.test.mock.MockContext;
import androidx.test.filters.SmallTest;
@@ -78,7 +81,13 @@ public class VpnManagerTest {
when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(false);
// Expect intent to be returned, as consent has not already been granted.
- assertNotNull(mVpnManager.provisionVpnProfile(profile));
+ final Intent intent = mVpnManager.provisionVpnProfile(profile);
+ assertNotNull(intent);
+
+ final ComponentName expectedComponentName =
+ ComponentName.unflattenFromString(
+ "com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
+ assertEquals(expectedComponentName, intent.getComponent());
verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 084ec7330236..155c61f3f8c7 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -63,6 +63,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.UidRange;
+import android.net.VpnManager;
import android.net.VpnService;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -471,12 +472,12 @@ public class VpnTest {
order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
// When a new VPN package is set the rules should change to cover that package.
- vpn.prepare(null, PKGS[0], false /* isPlatformVpn */);
+ vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
// When that VPN package is unset, everything should be undone again in reverse.
- vpn.prepare(null, VpnConfig.LEGACY_VPN, false /* isPlatformVpn */);
+ vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
}
@@ -817,6 +818,51 @@ public class VpnTest {
eq(TEST_VPN_PKG));
}
+ @Test
+ public void testSetPackageAuthorizationVpnService() throws Exception {
+ final Vpn vpn = createVpnAndSetupUidChecks();
+
+ assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
+ verify(mAppOps)
+ .setMode(
+ eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(Process.myUid()),
+ eq(TEST_VPN_PKG),
+ eq(AppOpsManager.MODE_ALLOWED));
+ }
+
+ @Test
+ public void testSetPackageAuthorizationPlatformVpn() throws Exception {
+ final Vpn vpn = createVpnAndSetupUidChecks();
+
+ assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
+ verify(mAppOps)
+ .setMode(
+ eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(Process.myUid()),
+ eq(TEST_VPN_PKG),
+ eq(AppOpsManager.MODE_ALLOWED));
+ }
+
+ @Test
+ public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
+ final Vpn vpn = createVpnAndSetupUidChecks();
+
+ assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
+ verify(mAppOps)
+ .setMode(
+ eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(Process.myUid()),
+ eq(TEST_VPN_PKG),
+ eq(AppOpsManager.MODE_IGNORED));
+ verify(mAppOps)
+ .setMode(
+ eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(Process.myUid()),
+ eq(TEST_VPN_PKG),
+ eq(AppOpsManager.MODE_IGNORED));
+ }
+
/**
* Mock some methods of vpn object.
*/