summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Benedict Wong <benedictwong@google.com> 2022-03-18 22:13:01 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2022-03-18 22:13:01 +0000
commit639c60d696d2558b9028a0804e3318e8ac56beba (patch)
treec021874d3edfac35b89769cbaba6d189d3024dc1
parent871629bd606399ac6cc1b1ea24e84f624731a4f4 (diff)
parentf1dacac9ea072ab9ca2f51fb6bc9544713348582 (diff)
Merge changes I67470903,Ia80da6d4,I332397f4 am: 7d042ad402 am: f1dacac9ea
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2030266 Change-Id: Ifc90d7d64ea65ebdc996f2fbc4ce0fb90eef2f3e
-rw-r--r--core/api/current.txt18
-rw-r--r--core/java/android/net/IVpnManager.aidl2
-rw-r--r--core/java/android/net/VpnManager.java32
-rw-r--r--core/java/android/net/VpnProfileState.aidl19
-rw-r--r--core/java/android/net/VpnProfileState.java153
-rw-r--r--services/core/java/com/android/server/VpnManagerService.java19
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java40
7 files changed, 283 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 0610446728d7..507919cc2bad 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -25503,11 +25503,13 @@ package android.net {
public class VpnManager {
method public void deleteProvisionedVpnProfile();
+ method @Nullable public android.net.VpnProfileState getProvisionedVpnProfileState();
method @Nullable public android.content.Intent provisionVpnProfile(@NonNull android.net.PlatformVpnProfile);
method @Deprecated public void startProvisionedVpnProfile();
method @NonNull public String startProvisionedVpnProfileSession();
method public void stopProvisionedVpnProfile();
field public static final String ACTION_VPN_MANAGER_EVENT = "android.net.action.VPN_MANAGER_EVENT";
+ field public static final String CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED = "android.net.category.EVENT_ALWAYS_ON_STATE_CHANGED";
field public static final String CATEGORY_EVENT_DEACTIVATED_BY_USER = "android.net.category.EVENT_DEACTIVATED_BY_USER";
field public static final String CATEGORY_EVENT_IKE_ERROR = "android.net.category.EVENT_IKE_ERROR";
field public static final String CATEGORY_EVENT_NETWORK_ERROR = "android.net.category.EVENT_NETWORK_ERROR";
@@ -25524,6 +25526,22 @@ package android.net {
field public static final String EXTRA_UNDERLYING_LINK_PROPERTIES = "android.net.extra.UNDERLYING_LINK_PROPERTIES";
field public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK";
field public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES = "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES";
+ field public static final String EXTRA_VPN_PROFILE_STATE = "android.net.extra.VPN_PROFILE_STATE";
+ }
+
+ public final class VpnProfileState implements android.os.Parcelable {
+ ctor public VpnProfileState(int, @Nullable String, boolean, boolean);
+ method public int describeContents();
+ method @Nullable public String getSessionId();
+ method public int getState();
+ method public boolean isAlwaysOn();
+ method public boolean isLockdownEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnProfileState> CREATOR;
+ field public static final int STATE_CONNECTED = 2; // 0x2
+ field public static final int STATE_CONNECTING = 1; // 0x1
+ field public static final int STATE_DISCONNECTED = 0; // 0x0
+ field public static final int STATE_FAILED = 3; // 0x3
}
public class VpnService extends android.app.Service {
diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl
index 070efa363cc0..b4647cabe1bc 100644
--- a/core/java/android/net/IVpnManager.aidl
+++ b/core/java/android/net/IVpnManager.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.net.Network;
+import android.net.VpnProfileState;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
@@ -40,6 +41,7 @@ interface IVpnManager {
void deleteVpnProfile(String packageName);
String startVpnProfile(String packageName);
void stopVpnProfile(String packageName);
+ VpnProfileState getProvisionedVpnProfileState(String packageName);
/** Always-on VPN APIs */
boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index c51444cd31b6..ae7d91f92cb7 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -161,6 +161,23 @@ public class VpnManager {
"android.net.category.EVENT_DEACTIVATED_BY_USER";
/**
+ * The always-on state of this VPN was changed
+ *
+ * <p>This may be the result of a user changing VPN settings, or a Device Policy Manager app
+ * having changed the VPN policy.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED =
+ "android.net.category.EVENT_ALWAYS_ON_STATE_CHANGED";
+
+ /**
+ * The VpnProfileState at the time that this event occurred.
+ *
+ * <p>This extra may be null if the VPN was revoked by the user, or the profile was deleted.
+ */
+ public static final String EXTRA_VPN_PROFILE_STATE = "android.net.extra.VPN_PROFILE_STATE";
+
+ /**
* The key of the session that experienced this event, as a {@code String}.
*
* This is the same key that was returned by {@link #startProvisionedVpnProfileSession}.
@@ -403,6 +420,21 @@ public class VpnManager {
}
/**
+ * Retrieve the VpnProfileState for the profile provisioned by the calling package.
+ *
+ * @return the VpnProfileState with current information, or null if there was no profile
+ * provisioned by the calling package.
+ */
+ @Nullable
+ public VpnProfileState getProvisionedVpnProfileState() {
+ try {
+ return mService.getProvisionedVpnProfileState(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets all VPN settings back to factory defaults.
* @hide
*/
diff --git a/core/java/android/net/VpnProfileState.aidl b/core/java/android/net/VpnProfileState.aidl
new file mode 100644
index 000000000000..add6386eda75
--- /dev/null
+++ b/core/java/android/net/VpnProfileState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 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;
+
+parcelable VpnProfileState; \ No newline at end of file
diff --git a/core/java/android/net/VpnProfileState.java b/core/java/android/net/VpnProfileState.java
new file mode 100644
index 000000000000..c69ea1a8c220
--- /dev/null
+++ b/core/java/android/net/VpnProfileState.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 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.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Describe the state of VPN.
+ */
+public final class VpnProfileState implements Parcelable {
+ /** The VPN has not been started, or some other VPN is active. */
+ public static final int STATE_DISCONNECTED = 0;
+ /** The VPN is attempting to connect, potentially after a failure. */
+ public static final int STATE_CONNECTING = 1;
+ /** The VPN was established successfully. */
+ public static final int STATE_CONNECTED = 2;
+ /** A non-recoverable error has occurred, and will not be retried. */
+ public static final int STATE_FAILED = 3;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STATE_"}, value = {
+ STATE_CONNECTED,
+ STATE_CONNECTING,
+ STATE_DISCONNECTED,
+ STATE_FAILED,
+ })
+ public @interface State {}
+
+ @State private final int mState;
+ private final String mSessionKey;
+ private final boolean mAlwaysOn;
+ private final boolean mLockdown;
+
+ public VpnProfileState(@State int state, @Nullable String sessionKey, boolean alwaysOn,
+ boolean lockdown) {
+ mState = state;
+ mSessionKey = sessionKey;
+ mAlwaysOn = alwaysOn;
+ mLockdown = lockdown;
+ }
+
+ /**
+ * Returns the state of the Platform VPN
+ *
+ * <p>This state represents the internal connection state of the VPN. This state may diverge
+ * from the VPN Network's state during error and recovery handling.
+ */
+ @State public int getState() {
+ return mState;
+ }
+
+ /**
+ * Retrieves the Session Key
+ *
+ * <p>The session key is an ephemeral key uniquely identifying the session for a Platform VPN.
+ * The lifetime of this key is tied to the lifetime of the VPN session. In other words,
+ * reprovisioning of the VPN profile, restarting of the device, or manually restarting the
+ * platform VPN session will result in a new VPN session, and a new key.
+ *
+ * @return the unique key for the platform VPN session, or null if it is not running.
+ */
+ @Nullable
+ public String getSessionId() {
+ return mSessionKey;
+ }
+
+ /**
+ * Returns the always-on status of the PlatformVpnProfile.
+ *
+ * <p>If the PlatformVpnProfile is set to be running in always-on mode, the system will ensure
+ * that the profile is always started, and restarting it when necessary (e.g. after reboot).
+ *
+ * <p>Always-on can be set by an appropriately privileged user via the Settings VPN menus, or by
+ * the Device Policy Manager app programmatically.
+ *
+ * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+ */
+ public boolean isAlwaysOn() {
+ return mAlwaysOn;
+ }
+
+ /**
+ * Returns the lockdown mode status of the PlatformVpnProfile.
+ *
+ * <p>In lockdown mode, the system will ensure that apps are not allowed to bypass the VPN,
+ * including during startup or failure of the VPN.
+ *
+ * <p>Lockdown mode can be set by an appropriately privileged user via the Settings VPN menus,
+ * or by the Device Policy Manager app programmatically.
+ *
+ * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
+ */
+ public boolean isLockdownEnabled() {
+ return mLockdown;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mState);
+ out.writeString(mSessionKey);
+ out.writeBoolean(mAlwaysOn);
+ out.writeBoolean(mLockdown);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<VpnProfileState> CREATOR =
+ new Parcelable.Creator<VpnProfileState>() {
+ public VpnProfileState createFromParcel(Parcel in) {
+ return new VpnProfileState(in);
+ }
+
+ public VpnProfileState[] newArray(int size) {
+ return new VpnProfileState[size];
+ }
+ };
+
+ private VpnProfileState(Parcel in) {
+ mState = in.readInt();
+ mSessionKey = in.readString();
+ mAlwaysOn = in.readBoolean();
+ mLockdown = in.readBoolean();
+ }
+}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 7b8cce54c8a7..c1d8e7bf3dc0 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -37,6 +37,7 @@ import android.net.NetworkStack;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
+import android.net.VpnProfileState;
import android.net.VpnService;
import android.net.util.NetdService;
import android.os.Binder;
@@ -374,6 +375,24 @@ public class VpnManagerService extends IVpnManager.Stub {
}
/**
+ * Retrieve the VpnProfileState for the profile provisioned by the given package.
+ *
+ * @return the VpnProfileState with current information, or null if there was no profile
+ * provisioned by the given package.
+ * @hide
+ */
+ @Override
+ @Nullable
+ public VpnProfileState getProvisionedVpnProfileState(@NonNull String packageName) {
+ final int callingUid = Binder.getCallingUid();
+ verifyCallingUidAndPackage(packageName, callingUid);
+ final int user = UserHandle.getUserId(callingUid);
+ synchronized (mVpns) {
+ return mVpns.get(user).getProvisionedVpnProfileState(packageName);
+ }
+ }
+
+ /**
* Start legacy VPN, controlling native daemons as needed. Creates a
* secondary thread to perform connection work, returning quickly.
*
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c0df095c3289..a6da4a6a4260 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -75,6 +75,7 @@ import android.net.RouteInfo;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
+import android.net.VpnProfileState;
import android.net.VpnService;
import android.net.VpnTransportInfo;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -3438,6 +3439,45 @@ public class Vpn {
}
}
+ private @VpnProfileState.State int getStateFromLegacyState(int legacyState) {
+ switch (legacyState) {
+ case LegacyVpnInfo.STATE_CONNECTING:
+ return VpnProfileState.STATE_CONNECTING;
+ case LegacyVpnInfo.STATE_CONNECTED:
+ return VpnProfileState.STATE_CONNECTED;
+ case LegacyVpnInfo.STATE_DISCONNECTED:
+ return VpnProfileState.STATE_DISCONNECTED;
+ case LegacyVpnInfo.STATE_FAILED:
+ return VpnProfileState.STATE_FAILED;
+ default:
+ Log.wtf(TAG, "Unhandled state " + legacyState
+ + ", treat it as STATE_DISCONNECTED");
+ return VpnProfileState.STATE_DISCONNECTED;
+ }
+ }
+
+ private VpnProfileState makeVpnProfileState() {
+ // TODO: mSessionKey will be moved to Ikev2VpnRunner once aosp/2007077 is merged, so after
+ // merging aosp/2007077, here should check Ikev2VpnRunner is null or not. Session key will
+ // be null if Ikev2VpnRunner is null.
+ return new VpnProfileState(getStateFromLegacyState(mLegacyState), mSessionKey, mAlwaysOn,
+ mLockdown);
+ }
+
+ /**
+ * Retrieve the VpnProfileState for the profile provisioned by the given package.
+ *
+ * @return the VpnProfileState with current information, or null if there was no profile
+ * provisioned by the given package.
+ */
+ @Nullable
+ public synchronized VpnProfileState getProvisionedVpnProfileState(
+ @NonNull String packageName) {
+ requireNonNull(packageName, "No package name provided");
+ enforceNotRestrictedUser();
+ return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileState() : null;
+ }
+
/**
* Proxy to allow testing
*