Merge "Add separate user consent for Platform VPNs"
This commit is contained in:
@@ -116,7 +116,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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -2708,7 +2708,11 @@
|
||||
<string name="config_customAdbPublicKeyConfirmationSecondaryUserComponent"
|
||||
>com.android.systemui/com.android.systemui.usb.UsbDebuggingSecondaryUserActivity</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>
|
||||
|
||||
|
||||
@@ -2233,6 +2233,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" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,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;
|
||||
@@ -4310,7 +4311,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;
|
||||
}
|
||||
@@ -4318,26 +4319,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7239,7 +7243,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
|
||||
@@ -7262,7 +7266,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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -2373,7 +2404,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user