• 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 android.net.http;
6 
7 import android.annotation.IntDef;
8 import android.annotation.SuppressLint;
9 
10 import androidx.annotation.NonNull;
11 import androidx.annotation.Nullable;
12 
13 import java.lang.annotation.Retention;
14 import java.lang.annotation.RetentionPolicy;
15 import java.time.Duration;
16 
17 /**
18  * A class configuring the HTTP connection migration functionality.
19  *
20  * <p>Connection migration stops open connections to servers from being destroyed when the
21  * client device switches its L4 connectivity (typically the IP address as a result of using
22  * a different network). This is particularly common with mobile devices losing
23  * wifi connectivity and switching to cellular data, or vice versa (a.k.a. the parking lot
24  * problem). QUIC uses connection identifiers which are independent of the underlying
25  * transport layer to make this possible. If the client connects to a new network and wants
26  * to preserve the existing connection, they can do so by using a connection identifier the server
27  * knows to be a continuation of the existing connection.
28  *
29  * <p>The features are only available for QUIC connections and the server needs to support
30  * connection migration.
31  *
32  * @see <a href="https://www.rfc-editor.org/rfc/rfc9000.html#section-9">Connection
33  *     Migration specification</a>
34  */
35 // SuppressLint to be consistent with other cronet code
36 @SuppressLint("UserHandleName")
37 public class ConnectionMigrationOptions {
38     private final @MigrationOptionState int mEnableDefaultNetworkMigration;
39     private final @MigrationOptionState int mEnablePathDegradationMigration;
40     @Nullable
41     private final Boolean mAllowServerMigration;
42     @Nullable
43     private final Boolean mMigrateIdleConnections;
44     @Nullable
45     private final Duration mIdleMigrationPeriod;
46     private final @MigrationOptionState int mAllowNonDefaultNetworkUsage;
47     @Nullable
48     private final Duration mMaxTimeOnNonDefaultNetwork;
49     @Nullable
50     private final Integer mMaxWriteErrorNonDefaultNetworkMigrationsCount;
51     @Nullable
52     private final Integer mMaxPathDegradingNonDefaultMigrationsCount;
53 
54     /**
55      * Option is unspecified, platform default value will be used.
56      */
57     public static final int MIGRATION_OPTION_UNSPECIFIED = 0;
58 
59     /**
60      * Option is enabled.
61      */
62     public static final int MIGRATION_OPTION_ENABLED = 1;
63 
64     /**
65      * Option is disabled.
66      */
67     public static final int MIGRATION_OPTION_DISABLED = 2;
68 
69     /** @hide */
70     @Retention(RetentionPolicy.SOURCE)
71     @IntDef(flag = false, prefix = "MIGRATION_OPTION_", value = {
72             MIGRATION_OPTION_UNSPECIFIED,
73             MIGRATION_OPTION_ENABLED,
74             MIGRATION_OPTION_DISABLED,
75     })
76     public @interface MigrationOptionState {}
77 
78     /**
79      * See {@link Builder#setDefaultNetworkMigration(int)}
80      */
getDefaultNetworkMigration()81     public @MigrationOptionState int getDefaultNetworkMigration() {
82         return mEnableDefaultNetworkMigration;
83     }
84 
85     /**
86      * See {@link Builder#setPathDegradationMigration(int)}
87      */
getPathDegradationMigration()88     public @MigrationOptionState int getPathDegradationMigration() {
89         return mEnablePathDegradationMigration;
90     }
91 
92     /**
93      * See {@link Builder#setAllowServerMigration}
94      *
95      * {@hide}
96      */
97     @Nullable
getAllowServerMigration()98     public Boolean getAllowServerMigration() {
99         return mAllowServerMigration;
100     }
101 
102     /**
103      * See {@link Builder#setMigrateIdleConnections}
104      *
105      * {@hide}
106      */
107     @Nullable
getMigrateIdleConnections()108     public Boolean getMigrateIdleConnections() {
109         return mMigrateIdleConnections;
110     }
111 
112     /**
113      * See {@link Builder#setIdleMigrationPeriodSeconds}
114      *
115      * {@hide}
116      */
117     @Nullable
getIdleMigrationPeriod()118     public Duration getIdleMigrationPeriod() {
119         return mIdleMigrationPeriod;
120     }
121 
122     /**
123      * See {@link Builder#setAllowNonDefaultNetworkUsage(int)}
124      */
getAllowNonDefaultNetworkUsage()125     public @MigrationOptionState int getAllowNonDefaultNetworkUsage() {
126         return mAllowNonDefaultNetworkUsage;
127     }
128 
129     /**
130      * See {@link Builder#setMaxTimeOnNonDefaultNetworkSeconds}
131      *
132      * {@hide}
133      */
134     @Nullable
getMaxTimeOnNonDefaultNetwork()135     public Duration getMaxTimeOnNonDefaultNetwork() {
136         return mMaxTimeOnNonDefaultNetwork;
137     }
138 
139     /**
140      * See {@link Builder#setMaxWriteErrorNonDefaultNetworkMigrationsCount}
141      *
142      * {@hide}
143      */
144     @Nullable
getMaxWriteErrorNonDefaultNetworkMigrationsCount()145     public Integer getMaxWriteErrorNonDefaultNetworkMigrationsCount() {
146         return mMaxWriteErrorNonDefaultNetworkMigrationsCount;
147     }
148 
149     /**
150      * See {@link Builder#setMaxPathDegradingNonDefaultNetworkMigrationsCount}
151      *
152      * {@hide}
153      */
154     @Nullable
getMaxPathDegradingNonDefaultMigrationsCount()155     public Integer getMaxPathDegradingNonDefaultMigrationsCount() {
156         return mMaxPathDegradingNonDefaultMigrationsCount;
157     }
158 
ConnectionMigrationOptions(@onNull Builder builder)159     ConnectionMigrationOptions(@NonNull Builder builder) {
160         this.mEnableDefaultNetworkMigration = builder.mEnableDefaultNetworkMigration;
161         this.mEnablePathDegradationMigration = builder.mEnablePathDegradationMigration;
162         this.mAllowServerMigration = builder.mAllowServerMigration;
163         this.mMigrateIdleConnections = builder.mMigrateIdleConnections;
164         this.mIdleMigrationPeriod = builder.mIdleConnectionMigrationPeriod;
165         this.mAllowNonDefaultNetworkUsage = builder.mAllowNonDefaultNetworkUsage;
166         this.mMaxTimeOnNonDefaultNetwork = builder.mMaxTimeOnNonDefaultNetwork;
167         this.mMaxWriteErrorNonDefaultNetworkMigrationsCount = builder.mMaxWriteErrorNonDefaultNetworkMigrationsCount;
168         this.mMaxPathDegradingNonDefaultMigrationsCount = builder.mMaxPathDegradingNonDefaultMigrationsCount;
169     }
170 
171     /**
172      * Builder for {@link ConnectionMigrationOptions}.
173      */
174     public static final class Builder {
175         private @MigrationOptionState int mEnableDefaultNetworkMigration;
176         private @MigrationOptionState int mEnablePathDegradationMigration;
177         @Nullable
178         private Boolean mAllowServerMigration;
179         @Nullable
180         private Boolean mMigrateIdleConnections;
181         @Nullable
182         private Duration mIdleConnectionMigrationPeriod;
183         private @MigrationOptionState int mAllowNonDefaultNetworkUsage;
184         @Nullable
185         private Duration mMaxTimeOnNonDefaultNetwork;
186         @Nullable
187         private Integer mMaxWriteErrorNonDefaultNetworkMigrationsCount;
188         @Nullable
189         private Integer mMaxPathDegradingNonDefaultMigrationsCount;
190 
Builder()191         public Builder() {}
192 
193         /**
194          * Sets whether to enable the possibility of migrating connections on default network
195          * change. If enabled, active QUIC connections will be migrated onto the new network when
196          * the platform indicates that the default network is changing.
197          *
198          * @see <a href="https://developer.android.com/training/basics/network-ops/reading-network-state#listening-events">Android
199          *     Network State</a>
200          *
201          * @param state one of the MIGRATION_OPTION_* values
202          * @return this builder for chaining
203          */
204         @NonNull
setDefaultNetworkMigration(@igrationOptionState int state)205         public Builder setDefaultNetworkMigration(@MigrationOptionState int state) {
206             this.mEnableDefaultNetworkMigration = state;
207             return this;
208         }
209 
210         /**
211          * Sets whether to enable the possibility of migrating connections if the current path is
212          * performing poorly.
213          *
214          * <p>Depending on other configuration, this can result to migrating the connections within
215          * the same default network, or to a non-default network.
216          *
217          * @param state one of the MIGRATION_OPTION_* values
218          * @return this builder for chaining
219          */
220         @NonNull
setPathDegradationMigration(@igrationOptionState int state)221         public Builder setPathDegradationMigration(@MigrationOptionState int state) {
222             this.mEnablePathDegradationMigration = state;
223             return this;
224         }
225 
226         /**
227          * Enables the possibility of migrating connections to an alternate server address
228          * at the server's request.
229          *
230          * @return this builder for chaining
231          *
232          * {@hide}
233          */
234         @Experimental
235         @NonNull
setAllowServerMigration(boolean allowServerMigration)236         public Builder setAllowServerMigration(boolean allowServerMigration) {
237             this.mAllowServerMigration = allowServerMigration;
238             return this;
239         }
240 
241         /**
242          * Configures whether migration of idle connections should be enabled or not.
243          *
244          * <p>If set to true, idle connections will be migrated too, as long as they haven't been
245          * idle for too long. The setting is shared for all connection migration types. The maximum
246          * idle period for which connections will still be migrated can be customized using {@link
247          * #setIdleMigrationPeriodSeconds}.
248          *
249          * @return this builder for chaining
250          *
251          * {@hide}
252          */
253         @Experimental
254         @NonNull
setMigrateIdleConnections(boolean migrateIdleConnections)255         public Builder setMigrateIdleConnections(boolean migrateIdleConnections) {
256             this.mMigrateIdleConnections = migrateIdleConnections;
257             return this;
258         }
259 
260         /**
261          * Sets the maximum idle period for which connections will still be migrated, in seconds.
262          * The setting is shared for all connection migration types.
263          *
264          * <p>Only relevant if {@link #setMigrateIdleConnections(boolean)} is enabled.
265          *
266          * @return this builder for chaining
267          *
268          * {@hide}
269          */
270         @Experimental
271         @NonNull
setIdleMigrationPeriodSeconds( @onNull Duration idleConnectionMigrationPeriod)272         public Builder setIdleMigrationPeriodSeconds(
273                 @NonNull Duration idleConnectionMigrationPeriod) {
274             this.mIdleConnectionMigrationPeriod = idleConnectionMigrationPeriod;
275             return this;
276         }
277 
278         /**
279          * Sets whether connections can be migrated to an alternate network when Cronet detects
280          * a degradation of the path currently in use. Requires setting
281          * {@link #setPathDegradationMigration(int)} to {@link #MIGRATION_OPTION_ENABLED} to
282          * have any effect.
283          *
284          * <p>Note: This setting can result in requests being sent on non-default metered networks,
285          * eating into the users' data budgets and incurring extra costs. Make sure you're using
286          * metered networks sparingly.
287          *
288          * @param state one of the MIGRATION_OPTION_* values
289          * @return this builder for chaining
290          */
291         @Experimental
292         @NonNull
setAllowNonDefaultNetworkUsage(@igrationOptionState int state)293         public Builder setAllowNonDefaultNetworkUsage(@MigrationOptionState int state) {
294             this.mAllowNonDefaultNetworkUsage = state;
295             return this;
296         }
297 
298         /**
299          * Sets the maximum period for which connections migrated to non-default networks remain
300          * there before they're migrated back. This time is not cumulative - each migration off
301          * the default network for each connection measures and compares to this value separately.
302          *
303          * <p>Only relevant if {@link #setAllowNonDefaultNetworkUsage(int)} is set to
304          * {@link #MIGRATION_OPTION_ENABLED}
305          *
306          * @return this builder for chaining
307          *
308          * {@hide}
309          */
310         @Experimental
311         @NonNull
setMaxTimeOnNonDefaultNetworkSeconds( @onNull Duration maxTimeOnNonDefaultNetwork)312         public Builder setMaxTimeOnNonDefaultNetworkSeconds(
313                 @NonNull Duration maxTimeOnNonDefaultNetwork) {
314             this.mMaxTimeOnNonDefaultNetwork = maxTimeOnNonDefaultNetwork;
315             return this;
316         }
317 
318         /**
319          * Sets the maximum number of migrations to the non-default network upon encountering write
320          * errors. Counted cumulatively per network per connection.
321          *
322          * <p>Only relevant if {@link #setAllowNonDefaultNetworkUsage(int)} is set to
323          * {@link #MIGRATION_OPTION_ENABLED}
324          *
325          * @return this builder for chaining
326          *
327          * {@hide}
328          */
329         @Experimental
330         @NonNull
setMaxWriteErrorNonDefaultNetworkMigrationsCount( int maxWriteErrorNonDefaultMigrationsCount)331         public Builder setMaxWriteErrorNonDefaultNetworkMigrationsCount(
332                 int maxWriteErrorNonDefaultMigrationsCount) {
333             this.mMaxWriteErrorNonDefaultNetworkMigrationsCount = maxWriteErrorNonDefaultMigrationsCount;
334             return this;
335         }
336 
337         /**
338          * Sets the maximum number of migrations to the non-default network upon encountering path
339          * degradation for the existing connection. Counted cumulatively per network per connection.
340          *
341          * <p>Only relevant if {@link #setAllowNonDefaultNetworkUsage(int)} is set to
342          * {@link #MIGRATION_OPTION_ENABLED}
343          *
344          * @return this builder for chaining
345          *
346          * {@hide}
347          */
348         @Experimental
349         @NonNull
setMaxPathDegradingNonDefaultNetworkMigrationsCount( int maxPathDegradingNonDefaultMigrationsCount)350         public Builder setMaxPathDegradingNonDefaultNetworkMigrationsCount(
351                 int maxPathDegradingNonDefaultMigrationsCount) {
352             this.mMaxPathDegradingNonDefaultMigrationsCount = maxPathDegradingNonDefaultMigrationsCount;
353             return this;
354         }
355 
356         /**
357          * Creates and returns the final {@link ConnectionMigrationOptions} instance, based on the
358          * values in this builder.
359          */
360         @NonNull
build()361         public ConnectionMigrationOptions build() {
362             return new ConnectionMigrationOptions(this);
363         }
364     }
365 
366     /**
367      * Creates a new builder for {@link ConnectionMigrationOptions}.
368      *
369      * {@hide}
370      */
371     @NonNull
builder()372     public static Builder builder() {
373         return new Builder();
374     }
375 
376     /**
377      * An annotation for APIs which are not considered stable yet.
378      *
379      * <p>Applications using experimental APIs must acknowledge that they're aware of using APIs
380      * that are not considered stable. The APIs might change functionality, break or cease to exist
381      * without notice.
382      *
383      * <p>It's highly recommended to reach out to Cronet maintainers ({@code net-dev@chromium.org})
384      * before using one of the APIs annotated as experimental outside of debugging
385      * and proof-of-concept code. Be ready to help to help polishing the API, or for a "sorry,
386      * really not production ready yet".
387      *
388      * <p>If you still want to use an experimental API in production, you're doing so at your
389      * own risk. You have been warned.
390      *
391      * {@hide}
392      */
393     public @interface Experimental {}
394 }
395