• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 package android.net.vcn;
17 
18 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
19 
20 import static com.android.internal.annotations.VisibleForTesting.Visibility;
21 
22 import android.annotation.IntDef;
23 import android.annotation.IntRange;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SuppressLint;
27 import android.net.Network;
28 import android.net.NetworkCapabilities;
29 import android.net.ipsec.ike.IkeTunnelConnectionParams;
30 import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtils;
31 import android.os.PersistableBundle;
32 import android.util.ArraySet;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.internal.util.ArrayUtils;
36 import com.android.internal.util.Preconditions;
37 import com.android.server.vcn.util.PersistableBundleUtils;
38 
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.Objects;
45 import java.util.Set;
46 import java.util.SortedSet;
47 import java.util.TreeSet;
48 import java.util.concurrent.TimeUnit;
49 
50 /**
51  * This class represents a configuration for a connection to a Virtual Carrier Network gateway.
52  *
53  * <p>Each VcnGatewayConnectionConfig represents a single logical connection to a carrier gateway,
54  * and may provide one or more telephony services (as represented by network capabilities). Each
55  * gateway is expected to provide mobility for a given session as the device roams across {@link
56  * Network}s.
57  *
58  * <p>A VCN connection based on this configuration will be brought up dynamically based on device
59  * settings, and filed NetworkRequests. Underlying Networks must provide INTERNET connectivity, and
60  * must be part of the subscription group under which this configuration is registered (see {@link
61  * VcnManager#setVcnConfig}).
62  *
63  * <p>As an abstraction of a cellular network, services that can be provided by a VCN network are
64  * limited to services provided by cellular networks:
65  *
66  * <ul>
67  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MMS}
68  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_SUPL}
69  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_DUN}
70  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_FOTA}
71  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_IMS}
72  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_CBS}
73  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_IA}
74  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_RCS}
75  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_XCAP}
76  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_EIMS}
77  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_INTERNET}
78  *   <li>{@link NetworkCapabilities#NET_CAPABILITY_MCX}
79  * </ul>
80  */
81 public final class VcnGatewayConnectionConfig {
82     // TODO: Use MIN_MTU_V6 once it is public, @hide
83     @VisibleForTesting(visibility = Visibility.PRIVATE)
84     static final int MIN_MTU_V6 = 1280;
85 
86     /**
87      * The set of allowed capabilities for exposed capabilities.
88      *
89      * @hide
90      */
91     public static final Set<Integer> ALLOWED_CAPABILITIES;
92 
93     static {
94         Set<Integer> allowedCaps = new ArraySet<>();
95         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS);
96         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL);
97         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN);
98         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA);
99         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS);
100         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS);
101         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA);
102         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS);
103         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP);
104         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS);
105         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET);
106         allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX);
107 
108         ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps);
109     }
110 
111     /** @hide */
112     @Retention(RetentionPolicy.SOURCE)
113     @IntDef(
114             prefix = {"NET_CAPABILITY_"},
115             value = {
116                 NetworkCapabilities.NET_CAPABILITY_MMS,
117                 NetworkCapabilities.NET_CAPABILITY_SUPL,
118                 NetworkCapabilities.NET_CAPABILITY_DUN,
119                 NetworkCapabilities.NET_CAPABILITY_FOTA,
120                 NetworkCapabilities.NET_CAPABILITY_IMS,
121                 NetworkCapabilities.NET_CAPABILITY_CBS,
122                 NetworkCapabilities.NET_CAPABILITY_IA,
123                 NetworkCapabilities.NET_CAPABILITY_RCS,
124                 NetworkCapabilities.NET_CAPABILITY_XCAP,
125                 NetworkCapabilities.NET_CAPABILITY_EIMS,
126                 NetworkCapabilities.NET_CAPABILITY_INTERNET,
127                 NetworkCapabilities.NET_CAPABILITY_MCX,
128             })
129     public @interface VcnSupportedCapability {}
130 
131     private static final int DEFAULT_MAX_MTU = 1500;
132 
133     /**
134      * The maximum number of retry intervals that may be specified.
135      *
136      * <p>Limited to ensure an upper bound on config sizes.
137      */
138     private static final int MAX_RETRY_INTERVAL_COUNT = 10;
139 
140     /**
141      * The minimum allowable repeating retry interval
142      *
143      * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater
144      * than this value.
145      *
146      * @see {@link Builder#setRetryIntervalsMillis()}
147      */
148     private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15);
149 
150     private static final long[] DEFAULT_RETRY_INTERVALS_MS =
151             new long[] {
152                 TimeUnit.SECONDS.toMillis(1),
153                 TimeUnit.SECONDS.toMillis(2),
154                 TimeUnit.SECONDS.toMillis(5),
155                 TimeUnit.SECONDS.toMillis(30),
156                 TimeUnit.MINUTES.toMillis(1),
157                 TimeUnit.MINUTES.toMillis(5),
158                 TimeUnit.MINUTES.toMillis(15)
159             };
160     private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
161     @NonNull private final String mGatewayConnectionName;
162 
163     private static final String TUNNEL_CONNECTION_PARAMS_KEY = "mTunnelConnectionParams";
164     @NonNull private IkeTunnelConnectionParams mTunnelConnectionParams;
165 
166     private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
167     @NonNull private final SortedSet<Integer> mExposedCapabilities;
168 
169     private static final String MAX_MTU_KEY = "mMaxMtu";
170     private final int mMaxMtu;
171 
172     private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
173     @NonNull private final long[] mRetryIntervalsMs;
174 
175     /** Builds a VcnGatewayConnectionConfig with the specified parameters. */
VcnGatewayConnectionConfig( @onNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams, @NonNull Set<Integer> exposedCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu)176     private VcnGatewayConnectionConfig(
177             @NonNull String gatewayConnectionName,
178             @NonNull IkeTunnelConnectionParams tunnelConnectionParams,
179             @NonNull Set<Integer> exposedCapabilities,
180             @NonNull long[] retryIntervalsMs,
181             @IntRange(from = MIN_MTU_V6) int maxMtu) {
182         mGatewayConnectionName = gatewayConnectionName;
183         mTunnelConnectionParams = tunnelConnectionParams;
184         mExposedCapabilities = new TreeSet(exposedCapabilities);
185         mRetryIntervalsMs = retryIntervalsMs;
186         mMaxMtu = maxMtu;
187 
188         validate();
189     }
190 
191     /** @hide */
192     @VisibleForTesting(visibility = Visibility.PRIVATE)
VcnGatewayConnectionConfig(@onNull PersistableBundle in)193     public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
194         final PersistableBundle tunnelConnectionParamsBundle =
195                 in.getPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY);
196         Objects.requireNonNull(
197                 tunnelConnectionParamsBundle, "tunnelConnectionParamsBundle was null");
198 
199         final PersistableBundle exposedCapsBundle =
200                 in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
201 
202         mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
203         mTunnelConnectionParams =
204                 TunnelConnectionParamsUtils.fromPersistableBundle(tunnelConnectionParamsBundle);
205         mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
206                 exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
207         mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
208         mMaxMtu = in.getInt(MAX_MTU_KEY);
209 
210         validate();
211     }
212 
validate()213     private void validate() {
214         Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null");
215         Objects.requireNonNull(mTunnelConnectionParams, "tunnel connection parameter was null");
216 
217         Preconditions.checkArgument(
218                 mExposedCapabilities != null && !mExposedCapabilities.isEmpty(),
219                 "exposedCapsBundle was null or empty");
220         for (Integer cap : getAllExposedCapabilities()) {
221             checkValidCapability(cap);
222         }
223 
224         Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
225         validateRetryInterval(mRetryIntervalsMs);
226 
227         Preconditions.checkArgument(
228                 mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
229     }
230 
checkValidCapability(int capability)231     private static void checkValidCapability(int capability) {
232         Preconditions.checkArgument(
233                 ALLOWED_CAPABILITIES.contains(capability),
234                 "NetworkCapability " + capability + "out of range");
235     }
236 
validateRetryInterval(@ullable long[] retryIntervalsMs)237     private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) {
238         Preconditions.checkArgument(
239                 retryIntervalsMs != null
240                         && retryIntervalsMs.length > 0
241                         && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT,
242                 "retryIntervalsMs was null, empty or exceed max interval count");
243 
244         final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1];
245         if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) {
246             throw new IllegalArgumentException(
247                     "Repeating retry interval was too short, must be a minimum of 15 minutes: "
248                             + repeatingInterval);
249         }
250     }
251 
252     /**
253      * Returns the configured Gateway Connection name.
254      *
255      * <p>This name is used by the configuring apps to distinguish between
256      * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as
257      * the identifier in VcnStatusCallback invocations.
258      *
259      * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
260      */
261     @NonNull
getGatewayConnectionName()262     public String getGatewayConnectionName() {
263         return mGatewayConnectionName;
264     }
265 
266     /**
267      * Returns tunnel connection parameters.
268      *
269      * @hide
270      */
271     @NonNull
getTunnelConnectionParams()272     public IkeTunnelConnectionParams getTunnelConnectionParams() {
273         return mTunnelConnectionParams;
274     }
275 
276     /**
277      * Returns all exposed capabilities.
278      *
279      * <p>The returned integer-value capabilities will not contain duplicates, and will be sorted in
280      * ascending numerical order.
281      *
282      * @see Builder#addExposedCapability(int)
283      * @see Builder#removeExposedCapability(int)
284      */
285     @NonNull
getExposedCapabilities()286     public int[] getExposedCapabilities() {
287         // Sorted set guarantees ordering
288         return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities));
289     }
290 
291     /**
292      * Returns all exposed capabilities.
293      *
294      * <p>Left to prevent the need to make major changes while changes are actively in flight.
295      *
296      * @deprecated use getExposedCapabilities() instead
297      * @hide
298      */
299     @Deprecated
300     @NonNull
getAllExposedCapabilities()301     public Set<Integer> getAllExposedCapabilities() {
302         return Collections.unmodifiableSet(mExposedCapabilities);
303     }
304 
305     /**
306      * Retrieves the configured retry intervals.
307      *
308      * @see Builder#setRetryIntervalsMillis(long[])
309      */
310     @NonNull
getRetryIntervalsMillis()311     public long[] getRetryIntervalsMillis() {
312         return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length);
313     }
314 
315     /**
316      * Retrieves the maximum MTU allowed for this Gateway Connection.
317      *
318      * @see Builder#setMaxMtu(int)
319      */
320     @IntRange(from = MIN_MTU_V6)
getMaxMtu()321     public int getMaxMtu() {
322         return mMaxMtu;
323     }
324 
325     /**
326      * Converts this config to a PersistableBundle.
327      *
328      * @hide
329      */
330     @NonNull
331     @VisibleForTesting(visibility = Visibility.PROTECTED)
toPersistableBundle()332     public PersistableBundle toPersistableBundle() {
333         final PersistableBundle result = new PersistableBundle();
334 
335         final PersistableBundle tunnelConnectionParamsBundle =
336                 TunnelConnectionParamsUtils.toPersistableBundle(mTunnelConnectionParams);
337         final PersistableBundle exposedCapsBundle =
338                 PersistableBundleUtils.fromList(
339                         new ArrayList<>(mExposedCapabilities),
340                         PersistableBundleUtils.INTEGER_SERIALIZER);
341 
342         result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
343         result.putPersistableBundle(TUNNEL_CONNECTION_PARAMS_KEY, tunnelConnectionParamsBundle);
344         result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
345         result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
346         result.putInt(MAX_MTU_KEY, mMaxMtu);
347 
348         return result;
349     }
350 
351     @Override
hashCode()352     public int hashCode() {
353         return Objects.hash(
354                 mGatewayConnectionName,
355                 mTunnelConnectionParams,
356                 mExposedCapabilities,
357                 Arrays.hashCode(mRetryIntervalsMs),
358                 mMaxMtu);
359     }
360 
361     @Override
equals(@ullable Object other)362     public boolean equals(@Nullable Object other) {
363         if (!(other instanceof VcnGatewayConnectionConfig)) {
364             return false;
365         }
366 
367         final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
368         return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
369                 && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams)
370                 && mExposedCapabilities.equals(rhs.mExposedCapabilities)
371                 && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
372                 && mMaxMtu == rhs.mMaxMtu;
373     }
374 
375     /**
376      * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
377      */
378     public static final class Builder {
379         @NonNull private final String mGatewayConnectionName;
380         @NonNull private final IkeTunnelConnectionParams mTunnelConnectionParams;
381         @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
382         @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
383         private int mMaxMtu = DEFAULT_MAX_MTU;
384 
385         // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent.
386         //       Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS
387         //       when on Cell.
388 
389         /**
390          * Construct a Builder object.
391          *
392          * @param gatewayConnectionName the String GatewayConnection name for this
393          *     VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link
394          *     VcnConfig} must be given a unique name. This name is used by the caller to
395          *     distinguish between VcnGatewayConnectionConfigs configured on a single {@link
396          *     VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
397          * @param tunnelConnectionParams the IKE tunnel connection configuration
398          * @throws IllegalArgumentException if the provided IkeTunnelConnectionParams is not
399          *     configured to support MOBIKE
400          * @see IkeTunnelConnectionParams
401          * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
402          */
Builder( @onNull String gatewayConnectionName, @NonNull IkeTunnelConnectionParams tunnelConnectionParams)403         public Builder(
404                 @NonNull String gatewayConnectionName,
405                 @NonNull IkeTunnelConnectionParams tunnelConnectionParams) {
406             Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
407             Objects.requireNonNull(tunnelConnectionParams, "tunnelConnectionParams was null");
408             if (!tunnelConnectionParams.getIkeSessionParams().hasIkeOption(IKE_OPTION_MOBIKE)) {
409                 throw new IllegalArgumentException(
410                         "MOBIKE must be configured for the provided IkeSessionParams");
411             }
412 
413             mGatewayConnectionName = gatewayConnectionName;
414             mTunnelConnectionParams = tunnelConnectionParams;
415         }
416 
417         /**
418          * Add a capability that this VCN Gateway Connection will support.
419          *
420          * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway
421          *     Connection (i.e., the capabilities that this VCN Gateway Connection will support).
422          * @return this {@link Builder} instance, for chaining
423          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
424          *     Connection
425          */
426         @NonNull
addExposedCapability(@cnSupportedCapability int exposedCapability)427         public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) {
428             checkValidCapability(exposedCapability);
429 
430             mExposedCapabilities.add(exposedCapability);
431             return this;
432         }
433 
434         /**
435          * Remove a capability that this VCN Gateway Connection will support.
436          *
437          * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway
438          *     Connection (i.e., the capabilities that this VCN Gateway Connection will support)
439          * @return this {@link Builder} instance, for chaining
440          * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
441          *     Connection
442          */
443         @NonNull
444         @SuppressLint("BuilderSetStyle") // For consistency with NetCaps.Builder add/removeCap
removeExposedCapability(@cnSupportedCapability int exposedCapability)445         public Builder removeExposedCapability(@VcnSupportedCapability int exposedCapability) {
446             checkValidCapability(exposedCapability);
447 
448             mExposedCapabilities.remove(exposedCapability);
449             return this;
450         }
451 
452         /**
453          * Set the retry interval between VCN establishment attempts upon successive failures.
454          *
455          * <p>The last retry interval will be repeated until safe mode is entered, or a connection
456          * is successfully established, at which point the retry timers will be reset. For power
457          * reasons, the last (repeated) retry interval MUST be at least 15 minutes.
458          *
459          * <p>Retry intervals MAY be subject to system power saving modes. That is to say that if
460          * the system enters a power saving mode, the retry may not occur until the device leaves
461          * the specified power saving mode. Intervals are sequential, and intervals will NOT be
462          * skipped if system power saving results in delaying retries (even if it exceed multiple
463          * retry intervals).
464          *
465          * <p>Each Gateway Connection will retry according to the retry intervals configured, but if
466          * safe mode is enabled, all Gateway Connection(s) will be disabled.
467          *
468          * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which
469          *     the VCN will attempt to retry a session initiation. The last (repeating) retry
470          *     interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m,
471          *     15m]}
472          * @return this {@link Builder} instance, for chaining
473          * @see VcnManager for additional discussion on fail-safe mode
474          */
475         @NonNull
setRetryIntervalsMillis(@onNull long[] retryIntervalsMs)476         public Builder setRetryIntervalsMillis(@NonNull long[] retryIntervalsMs) {
477             validateRetryInterval(retryIntervalsMs);
478 
479             mRetryIntervalsMs = retryIntervalsMs;
480             return this;
481         }
482 
483         /**
484          * Sets the maximum MTU allowed for this VCN Gateway Connection.
485          *
486          * <p>This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the
487          * MTU of the virtualized network.
488          *
489          * <p>The system may reduce the MTU below the maximum specified based on signals such as the
490          * MTU of the underlying networks (and adjusted for Gateway Connection overhead).
491          *
492          * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than
493          *     the IPv6 minimum MTU of 1280. Defaults to 1500.
494          * @return this {@link Builder} instance, for chaining
495          */
496         @NonNull
setMaxMtu(@ntRangefrom = MIN_MTU_V6) int maxMtu)497         public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) {
498             Preconditions.checkArgument(
499                     maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
500 
501             mMaxMtu = maxMtu;
502             return this;
503         }
504 
505         /**
506          * Builds and validates the VcnGatewayConnectionConfig.
507          *
508          * @return an immutable VcnGatewayConnectionConfig instance
509          */
510         @NonNull
build()511         public VcnGatewayConnectionConfig build() {
512             return new VcnGatewayConnectionConfig(
513                     mGatewayConnectionName,
514                     mTunnelConnectionParams,
515                     mExposedCapabilities,
516                     mRetryIntervalsMs,
517                     mMaxMtu);
518         }
519     }
520 }
521