• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.net;
6 
7 import androidx.annotation.Nullable;
8 import androidx.annotation.RequiresOptIn;
9 
10 /**
11  * A class configuring Cronet's connection migration functionality.
12  *
13  * <p>Connection migration stops open connections to servers from being destroyed when the
14  * client device switches its L4 connectivity (typically the IP address as a result of using
15  * a different network). This is particularly common with mobile devices losing
16  * wifi connectivity and switching to cellular data, or vice versa (a.k.a. the parking lot
17  * problem). QUIC uses connection identifiers which are independent of the underlying
18  * transport layer to make this possible. If the client connects to a new network and wants
19  * to preserve the existing connection, they can do so by using a connection identifier the server
20  * knows to be a continuation of the existing connection.
21  *
22  * <p>The features are only available for QUIC connections and the server needs to support
23  * connection migration.
24  *
25  * @see <a href="https://www.rfc-editor.org/rfc/rfc9000.html#section-9">Connection
26  *     Migration specification</a>
27  */
28 public class ConnectionMigrationOptions {
29     @Nullable private final Boolean mEnableDefaultNetworkMigration;
30     @Nullable private final Boolean mEnablePathDegradationMigration;
31     @Nullable private final Boolean mAllowServerMigration;
32     @Nullable private final Boolean mMigrateIdleConnections;
33     @Nullable private final Long mIdleMigrationPeriodSeconds;
34     @Nullable private final Boolean mRetryPreHandshakeErrorsOnAlternateNetwork;
35     @Nullable private final Boolean mAllowNonDefaultNetworkUsage;
36     @Nullable private final Long mMaxTimeOnNonDefaultNetworkSeconds;
37     @Nullable private final Integer mMaxWriteErrorEagerMigrationsCount;
38     @Nullable private final Integer mMaxPathDegradingEagerMigrationsCount;
39 
40     @Nullable
getEnableDefaultNetworkMigration()41     public Boolean getEnableDefaultNetworkMigration() {
42         return mEnableDefaultNetworkMigration;
43     }
44 
45     @Nullable
getEnablePathDegradationMigration()46     public Boolean getEnablePathDegradationMigration() {
47         return mEnablePathDegradationMigration;
48     }
49 
50     @Nullable
getAllowServerMigration()51     public Boolean getAllowServerMigration() {
52         return mAllowServerMigration;
53     }
54 
55     @Nullable
getMigrateIdleConnections()56     public Boolean getMigrateIdleConnections() {
57         return mMigrateIdleConnections;
58     }
59 
60     @Nullable
getIdleMigrationPeriodSeconds()61     public Long getIdleMigrationPeriodSeconds() {
62         return mIdleMigrationPeriodSeconds;
63     }
64 
65     @Nullable
getRetryPreHandshakeErrorsOnAlternateNetwork()66     public Boolean getRetryPreHandshakeErrorsOnAlternateNetwork() {
67         return mRetryPreHandshakeErrorsOnAlternateNetwork;
68     }
69 
70     @Nullable
getAllowNonDefaultNetworkUsage()71     public Boolean getAllowNonDefaultNetworkUsage() {
72         return mAllowNonDefaultNetworkUsage;
73     }
74 
75     @Nullable
getMaxTimeOnNonDefaultNetworkSeconds()76     public Long getMaxTimeOnNonDefaultNetworkSeconds() {
77         return mMaxTimeOnNonDefaultNetworkSeconds;
78     }
79 
80     @Nullable
getMaxWriteErrorEagerMigrationsCount()81     public Integer getMaxWriteErrorEagerMigrationsCount() {
82         return mMaxWriteErrorEagerMigrationsCount;
83     }
84 
85     @Nullable
getMaxPathDegradingEagerMigrationsCount()86     public Integer getMaxPathDegradingEagerMigrationsCount() {
87         return mMaxPathDegradingEagerMigrationsCount;
88     }
89 
ConnectionMigrationOptions(Builder builder)90     public ConnectionMigrationOptions(Builder builder) {
91         this.mEnableDefaultNetworkMigration = builder.mEnableDefaultNetworkConnectionMigration;
92         this.mEnablePathDegradationMigration = builder.mEnablePathDegradationMigration;
93         this.mAllowServerMigration = builder.mAllowServerMigration;
94         this.mMigrateIdleConnections = builder.mMigrateIdleConnections;
95         this.mIdleMigrationPeriodSeconds = builder.mIdleConnectionMigrationPeriodSeconds;
96         this.mRetryPreHandshakeErrorsOnAlternateNetwork =
97                 builder.mRetryPreHandshakeErrorsOnAlternateNetwork;
98         this.mAllowNonDefaultNetworkUsage = builder.mAllowNonDefaultNetworkUsage;
99         this.mMaxTimeOnNonDefaultNetworkSeconds = builder.mMaxTimeOnNonDefaultNetworkSeconds;
100         this.mMaxWriteErrorEagerMigrationsCount = builder.mMaxWriteErrorEagerMigrationsCount;
101         this.mMaxPathDegradingEagerMigrationsCount = builder.mMaxPathDegradingEagerMigrationsCount;
102     }
103 
104     /** Builder for {@link ConnectionMigrationOptions}. */
105     public static class Builder {
106         @Nullable private Boolean mEnableDefaultNetworkConnectionMigration;
107         @Nullable private Boolean mEnablePathDegradationMigration;
108         @Nullable private Boolean mAllowServerMigration;
109         @Nullable private Boolean mMigrateIdleConnections;
110         @Nullable private Long mIdleConnectionMigrationPeriodSeconds;
111         @Nullable private Boolean mRetryPreHandshakeErrorsOnAlternateNetwork;
112         @Nullable private Boolean mAllowNonDefaultNetworkUsage;
113         @Nullable private Long mMaxTimeOnNonDefaultNetworkSeconds;
114         @Nullable private Integer mMaxWriteErrorEagerMigrationsCount;
115         @Nullable private Integer mMaxPathDegradingEagerMigrationsCount;
116 
Builder()117         Builder() {}
118 
119         /**
120          * Enables the possibility of migrating connections on default network change. If enabled,
121          * active QUIC connections will be migrated onto the new network when the platform indicates
122          * that the default network is changing.
123          *
124          * @see <a href="https://developer.android.com/training/basics/network-ops/reading-network-state#listening-events">Android
125          *     Network State</a>
126          *
127          * @return this builder for chaining
128          */
enableDefaultNetworkMigration( boolean enableDefaultNetworkConnectionMigration)129         public Builder enableDefaultNetworkMigration(
130                 boolean enableDefaultNetworkConnectionMigration) {
131             this.mEnableDefaultNetworkConnectionMigration = enableDefaultNetworkConnectionMigration;
132             return this;
133         }
134 
135         /**
136          * Enables the possibility of migrating connections if the current path is performing
137          * poorly.
138          *
139          * <p>Depending on other configuration, this can result to migrating the connections within
140          * the same default network, or to a non-default network.
141          *
142          * @see #allowNonDefaultNetworkUsage(boolean)
143          *
144          * @return this builder for chaining
145          */
enablePathDegradationMigration(boolean enable)146         public Builder enablePathDegradationMigration(boolean enable) {
147             this.mEnablePathDegradationMigration = enable;
148             return this;
149         }
150 
151         /**
152          * Enables the possibility of migrating connections to an alternate server address
153          * at the server's request.
154          *
155          * @return this builder for chaining
156          */
157         @Experimental
allowServerMigration(boolean allowServerMigration)158         public Builder allowServerMigration(boolean allowServerMigration) {
159             this.mAllowServerMigration = allowServerMigration;
160             return this;
161         }
162 
163         /**
164          * Configures whether migration of idle connections should be enabled or not.
165          *
166          * <p>If set to true, idle connections will be migrated too, as long as they haven't been
167          * idle for too long. The setting is shared for all connection migration types. The maximum
168          * idle period for which connections will still be migrated can be customized using {@link
169          * #setIdleConnectionMigrationPeriodSeconds}.
170          *
171          * @return this builder for chaining
172          */
173         @Experimental
migrateIdleConnections(boolean migrateIdleConnections)174         public Builder migrateIdleConnections(boolean migrateIdleConnections) {
175             this.mMigrateIdleConnections = migrateIdleConnections;
176             return this;
177         }
178 
179         /**
180          * Sets the maximum idle period for which connections will still be migrated, in seconds.
181          * The setting is shared for all connection migration types.
182          *
183          * <p>Only relevant if {@link #migrateIdleConnections(boolean)} is enabled.
184          *
185          * @return this builder for chaining
186          */
187         @Experimental
setIdleConnectionMigrationPeriodSeconds( long idleConnectionMigrationPeriodSeconds)188         public Builder setIdleConnectionMigrationPeriodSeconds(
189                 long idleConnectionMigrationPeriodSeconds) {
190             this.mIdleConnectionMigrationPeriodSeconds = idleConnectionMigrationPeriodSeconds;
191             return this;
192         }
193 
194         /**
195          * Sets whether connections can be migrated to an alternate network when Cronet detects
196          * a degradation of the path currently in use.
197          *
198          * <p>Note: This setting can result in requests being sent on non-default metered networks.
199          * Make sure you're using metered networks sparingly, and fine tune parameters like
200          * {@link #setMaxPathDegradingNonDefaultNetworkMigrationsCount(int)}
201          * and {@link #setMaxTimeOnNonDefaultNetworkSeconds} to limit the time on non-default
202          * networks.
203          *
204          * @return this builder for chaining
205          */
206         @Experimental
allowNonDefaultNetworkUsage(boolean enable)207         public Builder allowNonDefaultNetworkUsage(boolean enable) {
208             this.mAllowNonDefaultNetworkUsage = enable;
209             return this;
210         }
211 
212         /**
213          * Sets the maximum period for which eagerly migrated connections should remain on the
214          * non-default network before they're migrated back. This time is not cumulative - each
215          * migration off the default network for each connection measures and compares to this value
216          * separately.
217          *
218          * <p>Only relevant if {@link #allowNonDefaultNetworkUsage(boolean)} is enabled.
219          *
220          * @return this builder for chaining
221          */
222         @Experimental
setMaxTimeOnNonDefaultNetworkSeconds( long maxTimeOnNonDefaultNetworkSeconds)223         public Builder setMaxTimeOnNonDefaultNetworkSeconds(
224                 long maxTimeOnNonDefaultNetworkSeconds) {
225             this.mMaxTimeOnNonDefaultNetworkSeconds = maxTimeOnNonDefaultNetworkSeconds;
226             return this;
227         }
228 
229         /**
230          * Sets the maximum number of migrations to the non-default network upon encountering write
231          * errors. Counted cumulatively per network per connection.
232          *
233          * <p>Only relevant if {@link #allowNonDefaultNetworkUsage(boolean)} is enabled.
234          *
235          * @return this builder for chaining
236          */
237         @Experimental
setMaxWriteErrorNonDefaultNetworkMigrationsCount( int maxWriteErrorEagerMigrationsCount)238         public Builder setMaxWriteErrorNonDefaultNetworkMigrationsCount(
239                 int maxWriteErrorEagerMigrationsCount) {
240             this.mMaxWriteErrorEagerMigrationsCount = maxWriteErrorEagerMigrationsCount;
241             return this;
242         }
243 
244         /**
245          * Sets the maximum number of migrations to the non-default network upon encountering path
246          * degradation for the existing connection. Counted cumulatively per network per connection.
247          *
248          * <p>Only relevant if {@link #allowNonDefaultNetworkUsage(boolean)} is enabled.
249          *
250          * @return this builder for chaining
251          */
252         @Experimental
setMaxPathDegradingNonDefaultNetworkMigrationsCount( int maxPathDegradingEagerMigrationsCount)253         public Builder setMaxPathDegradingNonDefaultNetworkMigrationsCount(
254                 int maxPathDegradingEagerMigrationsCount) {
255             this.mMaxPathDegradingEagerMigrationsCount = maxPathDegradingEagerMigrationsCount;
256             return this;
257         }
258 
259         /**
260          * Sets whether connections with pre-handshake errors should be retried on an alternative
261          * network.
262          *
263          * <p>If true, a new connection may be established an alternate network if it fails
264          * on the default network before handshake is confirmed.
265          *
266          * <p>Note: similarly to {@link #allowNonDefaultNetworkUsage(boolean)} this setting can
267          * result in requests being sent on non-default metered networks. Use with caution!
268          *
269          * @return this builder for chaining
270          */
271         @Experimental
retryPreHandshakeErrorsOnNonDefaultNetwork( boolean retryPreHandshakeErrorsOnAlternateNetwork)272         public Builder retryPreHandshakeErrorsOnNonDefaultNetwork(
273                 boolean retryPreHandshakeErrorsOnAlternateNetwork) {
274             this.mRetryPreHandshakeErrorsOnAlternateNetwork =
275                     retryPreHandshakeErrorsOnAlternateNetwork;
276             return this;
277         }
278 
279         /**
280          * Creates and returns the final {@link ConnectionMigrationOptions} instance, based on the
281          * values in this builder.
282          */
build()283         public ConnectionMigrationOptions build() {
284             return new ConnectionMigrationOptions(this);
285         }
286     }
287 
builder()288     public static Builder builder() {
289         return new Builder();
290     }
291 
292     /**
293      * An annotation for APIs which are not considered stable yet.
294      *
295      * <p>Experimental APIs are subject to change, breakage, or removal at any time and may not be
296      * production ready.
297      *
298      * <p>It's highly recommended to reach out to Cronet maintainers
299      * (<code>net-dev@chromium.org</code>) before using one of the APIs annotated as experimental
300      * outside of debugging and proof-of-concept code.
301      *
302      * <p>By using an Experimental API, applications acknowledge that they are doing so at their own
303      * risk.
304      */
305     @RequiresOptIn
306     public @interface Experimental {}
307 }
308