summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/VpnTransportInfo.java79
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkCapabilities.java2
-rw-r--r--packages/Connectivity/framework/src/android/net/VpnManager.java22
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java32
-rw-r--r--tests/net/java/android/net/VpnTransportInfoTest.java51
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java9
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java15
8 files changed, 193 insertions, 19 deletions
diff --git a/core/java/android/net/VpnTransportInfo.java b/core/java/android/net/VpnTransportInfo.java
new file mode 100644
index 000000000000..082fa58f8ac2
--- /dev/null
+++ b/core/java/android/net/VpnTransportInfo.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 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 android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.internal.util.MessageUtils;
+
+import java.util.Objects;
+
+/** @hide */
+public final class VpnTransportInfo implements TransportInfo, Parcelable {
+ private static final SparseArray<String> sTypeToString =
+ MessageUtils.findMessageNames(new Class[]{VpnManager.class}, new String[]{"TYPE_VPN_"});
+
+ /** Type of this VPN. */
+ @VpnManager.VpnType public final int type;
+
+ public VpnTransportInfo(@VpnManager.VpnType int type) {
+ this.type = type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof VpnTransportInfo)) return false;
+
+ VpnTransportInfo that = (VpnTransportInfo) o;
+ return this.type == that.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type);
+ }
+
+ @Override
+ public String toString() {
+ final String typeString = sTypeToString.get(type, "VPN_TYPE_???");
+ return String.format("VpnTransportInfo{%s}", typeString);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(type);
+ }
+
+ public static final @NonNull Creator<VpnTransportInfo> CREATOR =
+ new Creator<VpnTransportInfo>() {
+ public VpnTransportInfo createFromParcel(Parcel in) {
+ return new VpnTransportInfo(in.readInt());
+ }
+ public VpnTransportInfo[] newArray(int size) {
+ return new VpnTransportInfo[size];
+ }
+ };
+}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 55b2c3c9e11f..9d67f0b84367 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -762,12 +762,14 @@ public final class NetworkCapabilities implements Parcelable {
final int originalSignalStrength = mSignalStrength;
final int originalOwnerUid = getOwnerUid();
final int[] originalAdministratorUids = getAdministratorUids();
+ final TransportInfo originalTransportInfo = getTransportInfo();
clearAll();
mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS)
| (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
+ mTransportInfo = originalTransportInfo;
// Only retain the owner and administrator UIDs if they match the app registering the remote
// caller that registered the network.
diff --git a/packages/Connectivity/framework/src/android/net/VpnManager.java b/packages/Connectivity/framework/src/android/net/VpnManager.java
index 1812509ba6d2..1e30283a9e6c 100644
--- a/packages/Connectivity/framework/src/android/net/VpnManager.java
+++ b/packages/Connectivity/framework/src/android/net/VpnManager.java
@@ -55,13 +55,29 @@ import java.security.GeneralSecurityException;
public class VpnManager {
/** Type representing a lack of VPN @hide */
public static final int TYPE_VPN_NONE = -1;
- /** VPN service type code @hide */
+
+ /**
+ * A VPN created by an app using the {@link VpnService} API.
+ * @hide
+ */
public static final int TYPE_VPN_SERVICE = 1;
- /** Platform VPN type code @hide */
+
+ /**
+ * A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}.
+ * @hide
+ */
public static final int TYPE_VPN_PLATFORM = 2;
+ /**
+ * An IPsec VPN created by the built-in LegacyVpnRunner.
+ * @deprecated new Android devices should use VPN_TYPE_PLATFORM instead.
+ * @hide
+ */
+ @Deprecated
+ public static final int TYPE_VPN_LEGACY = 3;
+
/** @hide */
- @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
+ @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY})
@Retention(RetentionPolicy.SOURCE)
public @interface VpnType {}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5164437b6852..f59b9fc4ef46 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -8505,7 +8505,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final Vpn vpn = enforceActiveVpnOrNetworkStackPermission();
// Only VpnService based VPNs should be able to get this information.
- if (vpn != null && vpn.getActiveAppVpnType() != VpnManager.TYPE_VPN_SERVICE) {
+ if (vpn != null && vpn.getActiveVpnType() != VpnManager.TYPE_VPN_SERVICE) {
throw new SecurityException(
"getConnectionOwnerUid() not allowed for non-VpnService VPNs");
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index fc2c7e01efde..33c19b1ca2b2 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -74,6 +74,7 @@ import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
import android.net.VpnService;
+import android.net.VpnTransportInfo;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
@@ -435,6 +436,7 @@ public class Vpn {
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
loadAlwaysOnPackage(keyStore);
}
@@ -929,6 +931,7 @@ public class Vpn {
jniReset(mInterface);
mInterface = null;
mNetworkCapabilities.setUids(null);
+ mNetworkCapabilities.setTransportInfo(null);
}
// Revoke the connection or stop the VpnRunner.
@@ -999,6 +1002,8 @@ public class Vpn {
case VpnManager.TYPE_VPN_SERVICE:
toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN};
break;
+ case VpnManager.TYPE_VPN_LEGACY:
+ return false;
default:
Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
return false;
@@ -1029,6 +1034,8 @@ public class Vpn {
return isVpnServicePreConsented(context, packageName);
case VpnManager.TYPE_VPN_PLATFORM:
return isVpnProfilePreConsented(context, packageName);
+ case VpnManager.TYPE_VPN_LEGACY:
+ return VpnConfig.LEGACY_VPN.equals(packageName);
default:
return false;
}
@@ -1211,6 +1218,8 @@ public class Vpn {
mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+
// Only apps targeting Q and above can explicitly declare themselves as metered.
// These VPNs are assumed metered unless they state otherwise.
if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
@@ -1736,6 +1745,7 @@ public class Vpn {
private void cleanupVpnStateLocked() {
mStatusIntent = null;
mNetworkCapabilities.setUids(null);
+ mNetworkCapabilities.setTransportInfo(null);
mConfig = null;
mInterface = null;
@@ -1846,22 +1856,18 @@ public class Vpn {
}
/**
- * Gets the currently running App-based VPN type
+ * Gets the currently running VPN type
*
- * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running an
- * app-based VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
+ * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running a
+ * VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
* Settings-based, the Platform VPNs can be initiated by both apps and Settings.
*/
- public synchronized int getActiveAppVpnType() {
- if (VpnConfig.LEGACY_VPN.equals(mPackage)) {
- return VpnManager.TYPE_VPN_NONE;
- }
-
- if (mVpnRunner != null && mVpnRunner instanceof IkeV2VpnRunner) {
- return VpnManager.TYPE_VPN_PLATFORM;
- } else {
- return VpnManager.TYPE_VPN_SERVICE;
- }
+ public synchronized int getActiveVpnType() {
+ if (!mNetworkInfo.isConnectedOrConnecting()) return VpnManager.TYPE_VPN_NONE;
+ if (mVpnRunner == null) return VpnManager.TYPE_VPN_SERVICE;
+ return mVpnRunner instanceof IkeV2VpnRunner
+ ? VpnManager.TYPE_VPN_PLATFORM
+ : VpnManager.TYPE_VPN_LEGACY;
}
private void updateAlwaysOnNotification(DetailedState networkState) {
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
new file mode 100644
index 000000000000..2fd5e3861cef
--- /dev/null
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 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 android.net;
+
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VpnTransportInfoTest {
+
+ @Test
+ public void testParceling() {
+ VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ assertParcelSane(v, 1 /* fieldCount */);
+ assertParcelingIsLossless(v);
+ }
+
+ @Test
+ public void testEqualsAndHashCode() {
+ VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
+ VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ assertNotEquals(v1, v2);
+ assertEquals(v1, v3);
+ assertEquals(v1.hashCode(), v3.hashCode());
+ }
+} \ No newline at end of file
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ecdc62174ec0..d5d7b475fdb5 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -205,6 +205,7 @@ import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
+import android.net.VpnTransportInfo;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
@@ -1110,7 +1111,7 @@ public class ConnectivityServiceTest {
}
@Override
- public int getActiveAppVpnType() {
+ public int getActiveVpnType() {
return mVpnType;
}
@@ -1123,10 +1124,12 @@ public class ConnectivityServiceTest {
private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
throws Exception {
if (mAgentRegistered) throw new IllegalStateException("already registered");
+ updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
mConfig = new VpnConfig();
setUids(uids);
if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
mInterface = VPN_IFNAME;
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
@@ -7322,6 +7325,7 @@ public class ConnectivityServiceTest {
}
private void establishLegacyLockdownVpn() throws Exception {
+ mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
// The legacy lockdown VPN only supports userId 0.
final Set<UidRange> ranges = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.registerAgent(ranges);
@@ -7434,6 +7438,9 @@ public class ConnectivityServiceTest {
assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI));
assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
+ VpnTransportInfo ti = (VpnTransportInfo) vpnNc.getTransportInfo();
+ assertNotNull(ti);
+ assertEquals(VpnManager.TYPE_VPN_LEGACY, ti.type);
// Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
final LinkProperties wifiLp = new LinkProperties();
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 73cc9f129e79..cffd2d1d428f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.NetworkCallback;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -74,6 +75,7 @@ import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnService;
+import android.net.VpnTransportInfo;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.os.Build.VERSION_CODES;
@@ -984,6 +986,13 @@ public class VpnTest {
startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
}
+ private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
+ assertNotNull(nc);
+ VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
+ assertNotNull(ti);
+ assertEquals(type, ti.type);
+ }
+
public void startRacoon(final String serverAddr, final String expectedAddr)
throws Exception {
final ConditionVariable legacyRunnerReady = new ConditionVariable();
@@ -1020,8 +1029,10 @@ public class VpnTest {
// Now wait for the runner to be ready before testing for the route.
ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
+ ArgumentCaptor<NetworkCapabilities> ncCaptor =
+ ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- lpCaptor.capture(), any(), anyInt(), any(), anyInt());
+ lpCaptor.capture(), ncCaptor.capture(), anyInt(), any(), anyInt());
// In this test the expected address is always v4 so /32.
// Note that the interface needs to be specified because RouteInfo objects stored in
@@ -1031,6 +1042,8 @@ public class VpnTest {
final List<RouteInfo> actualRoutes = lpCaptor.getValue().getRoutes();
assertTrue("Expected throw route (" + expectedRoute + ") not found in " + actualRoutes,
actualRoutes.contains(expectedRoute));
+
+ assertTransportInfoMatches(ncCaptor.getValue(), VpnManager.TYPE_VPN_LEGACY);
} finally {
// Now interrupt the thread, unblock the runner and clean up.
vpn.mVpnRunner.exitVpnRunner();