1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.Objects;
28 import java.util.StringJoiner;
29 
30 /**
31  * Describe the state of VPN.
32  */
33 public final class VpnProfileState implements Parcelable {
34     /** The VPN has not been started, or some other VPN is active. */
35     public static final int STATE_DISCONNECTED = 0;
36     /** The VPN is attempting to connect, potentially after a failure. */
37     public static final int STATE_CONNECTING = 1;
38     /** The VPN was established successfully. */
39     public static final int STATE_CONNECTED = 2;
40     /** A non-recoverable error has occurred, and will not be retried. */
41     public static final int STATE_FAILED = 3;
42     /** @hide */
43     @Retention(RetentionPolicy.SOURCE)
44     @IntDef(prefix = {"STATE_"}, value = {
45             STATE_CONNECTED,
46             STATE_CONNECTING,
47             STATE_DISCONNECTED,
48             STATE_FAILED,
49     })
50     public @interface State {}
51 
52     @State private final int mState;
53     private final String mSessionKey;
54     private final boolean mAlwaysOn;
55     private final boolean mLockdown;
56 
VpnProfileState(@tate int state, @Nullable String sessionKey, boolean alwaysOn, boolean lockdown)57     public VpnProfileState(@State int state, @Nullable String sessionKey, boolean alwaysOn,
58             boolean lockdown) {
59         mState = state;
60         mSessionKey = sessionKey;
61         mAlwaysOn = alwaysOn;
62         mLockdown = lockdown;
63     }
64 
65     /**
66      * Returns the state of the Platform VPN
67      *
68      * <p>This state represents the internal connection state of the VPN. This state may diverge
69      * from the VPN Network's state during error and recovery handling.
70      */
getState()71     @State public int getState() {
72         return mState;
73     }
74 
75     /**
76      * Retrieves the Session Key
77      *
78      * <p>The session key is an ephemeral key uniquely identifying the session for a Platform VPN.
79      * The lifetime of this key is tied to the lifetime of the VPN session. In other words,
80      * reprovisioning of the VPN profile, restarting of the device, or manually restarting the
81      * platform VPN session will result in a new VPN session, and a new key.
82      *
83      * @return the unique key for the platform VPN session, or null if it is not running.
84      */
85     @Nullable
getSessionId()86     public String getSessionId() {
87         return mSessionKey;
88     }
89 
90     /**
91      * Returns the always-on status of the PlatformVpnProfile.
92      *
93      * <p>If the PlatformVpnProfile is set to be running in always-on mode, the system will ensure
94      * that the profile is always started, and restarting it when necessary (e.g. after reboot).
95      *
96      * <p>Always-on can be set by an appropriately privileged user via the Settings VPN menus, or by
97      * the Device Policy Manager app programmatically.
98      *
99      * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
100      */
isAlwaysOn()101     public boolean isAlwaysOn() {
102         return mAlwaysOn;
103     }
104 
105     /**
106      * Returns the lockdown mode status of the PlatformVpnProfile.
107      *
108      * <p>In lockdown mode, the system will ensure that apps are not allowed to bypass the VPN,
109      * including during startup or failure of the VPN.
110      *
111      * <p>Lockdown mode can be set by an appropriately privileged user via the Settings VPN menus,
112      * or by the Device Policy Manager app programmatically.
113      *
114      * See DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
115      */
isLockdownEnabled()116     public boolean isLockdownEnabled() {
117         return mLockdown;
118     }
119 
120     /**
121      * Implement the Parcelable interface
122      */
describeContents()123     public int describeContents() {
124         return 0;
125     }
126 
127     /**
128      * Implement the Parcelable interface
129      */
writeToParcel(@onNull Parcel out, int flags)130     public void writeToParcel(@NonNull Parcel out, int flags) {
131         out.writeInt(mState);
132         out.writeString(mSessionKey);
133         out.writeBoolean(mAlwaysOn);
134         out.writeBoolean(mLockdown);
135     }
136 
137     @NonNull
138     public static final Parcelable.Creator<VpnProfileState> CREATOR =
139             new Parcelable.Creator<VpnProfileState>() {
140                 public VpnProfileState createFromParcel(Parcel in) {
141                     return new VpnProfileState(in);
142                 }
143 
144                 public VpnProfileState[] newArray(int size) {
145                     return new VpnProfileState[size];
146                 }
147             };
148 
VpnProfileState(Parcel in)149     private VpnProfileState(Parcel in) {
150         mState = in.readInt();
151         mSessionKey = in.readString();
152         mAlwaysOn = in.readBoolean();
153         mLockdown = in.readBoolean();
154     }
155 
convertStateToString(@tate int state)156     private String convertStateToString(@State int state) {
157         switch (state) {
158             case STATE_CONNECTED:
159                 return "CONNECTED";
160             case STATE_CONNECTING:
161                 return "CONNECTING";
162             case STATE_DISCONNECTED:
163                 return "DISCONNECTED";
164             case STATE_FAILED:
165                 return "FAILED";
166             default:
167                 return "UNKNOWN";
168         }
169     }
170 
171     @Override
toString()172     public String toString() {
173         final StringJoiner resultJoiner = new StringJoiner(", ", "{", "}");
174         resultJoiner.add("State: " + convertStateToString(getState()));
175         resultJoiner.add("SessionId: " + getSessionId());
176         resultJoiner.add("Always-on: " + isAlwaysOn());
177         resultJoiner.add("Lockdown: " + isLockdownEnabled());
178         return resultJoiner.toString();
179     }
180 
181     @Override
equals(@ullable Object obj)182     public boolean equals(@Nullable Object obj) {
183         if (!(obj instanceof VpnProfileState)) return false;
184         final VpnProfileState that = (VpnProfileState) obj;
185         return (getState() == that.getState()
186                 && Objects.equals(getSessionId(), that.getSessionId())
187                 && isAlwaysOn() == that.isAlwaysOn()
188                 && isLockdownEnabled() == that.isLockdownEnabled());
189     }
190 
191     @Override
hashCode()192     public int hashCode() {
193         return Objects.hash(getState(), getSessionId(), isAlwaysOn(), isLockdownEnabled());
194     }
195 }
196