• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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 android.content.Context;
8 import android.net.http.HttpResponseCache;
9 import android.util.Log;
10 
11 import androidx.annotation.VisibleForTesting;
12 
13 import java.io.IOException;
14 import java.lang.reflect.Method;
15 import java.net.URL;
16 import java.net.URLConnection;
17 import java.net.URLStreamHandlerFactory;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.Date;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Set;
25 import java.util.concurrent.Executor;
26 
27 import javax.net.ssl.HttpsURLConnection;
28 
29 /**
30  * An engine to process {@link UrlRequest}s, which uses the best HTTP stack available on the current
31  * platform. An instance of this class can be created using {@link Builder}.
32  */
33 public abstract class CronetEngine {
34     private static final String TAG = CronetEngine.class.getSimpleName();
35 
36     /** The value of the active request count is unknown */
37     public static final int ACTIVE_REQUEST_COUNT_UNKNOWN = -1;
38 
39     /** The value of a connection metric is unknown. */
40     public static final int CONNECTION_METRIC_UNKNOWN = -1;
41 
42     /**
43      * The estimate of the effective connection type is unknown.
44      *
45      * @see #getEffectiveConnectionType
46      */
47     public static final int EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0;
48 
49     /**
50      * The device is offline.
51      *
52      * @see #getEffectiveConnectionType
53      */
54     public static final int EFFECTIVE_CONNECTION_TYPE_OFFLINE = 1;
55 
56     /**
57      * The estimate of the effective connection type is slow 2G.
58      *
59      * @see #getEffectiveConnectionType
60      */
61     public static final int EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 2;
62 
63     /**
64      * The estimate of the effective connection type is 2G.
65      *
66      * @see #getEffectiveConnectionType
67      */
68     public static final int EFFECTIVE_CONNECTION_TYPE_2G = 3;
69 
70     /**
71      * The estimate of the effective connection type is 3G.
72      *
73      * @see #getEffectiveConnectionType
74      */
75     public static final int EFFECTIVE_CONNECTION_TYPE_3G = 4;
76 
77     /**
78      * The estimate of the effective connection type is 4G.
79      *
80      * @see #getEffectiveConnectionType
81      */
82     public static final int EFFECTIVE_CONNECTION_TYPE_4G = 5;
83 
84     /** The value to be used to undo any previous network binding. */
85     public static final long UNBIND_NETWORK_HANDLE = -1;
86 
87     /**
88      * A builder for {@link CronetEngine}s, which allows runtime configuration of {@code
89      * CronetEngine}. Configuration options are set on the builder and then {@link #build} is called
90      * to create the {@code CronetEngine}.
91      */
92     // NOTE(kapishnikov): In order to avoid breaking the existing API clients, all future methods
93     // added to this class and other API classes must have default implementation.
94     public static class Builder {
95         private static final String TAG = "CronetEngine.Builder";
96 
97         /**
98          * A class which provides a method for loading the cronet native library. Apps needing to
99          * implement custom library loading logic can inherit from this class and pass an instance
100          * to
101          * {@link CronetEngine.Builder#setLibraryLoader}. For example, this might be required to
102          * work around {@code UnsatisfiedLinkError}s caused by flaky installation on certain older
103          * devices.
104          */
105         public abstract static class LibraryLoader {
106             /**
107              * Loads the native library.
108              *
109              * @param libName name of the library to load
110              */
loadLibrary(String libName)111             public abstract void loadLibrary(String libName);
112         }
113 
114         /** Reference to the actual builder implementation. {@hide exclude from JavaDoc}. */
115         protected final ICronetEngineBuilder mBuilderDelegate;
116 
117         /**
118          * Constructs a {@link Builder} object that facilitates creating a {@link CronetEngine}. The
119          * default configuration enables HTTP/2 and QUIC, but disables the HTTP cache.
120          *
121          * @param context Android {@link Context}, which is used by {@link Builder} to retrieve the
122          * application context. A reference to only the application context will be kept, so as to
123          * avoid extending the lifetime of {@code context} unnecessarily.
124          */
Builder(Context context)125         public Builder(Context context) {
126             this(createBuilderDelegate(context));
127         }
128 
129         /**
130          * Constructs {@link Builder} with a given delegate that provides the actual implementation
131          * of the {@code Builder} methods. This constructor is used only by the internal
132          * implementation.
133          *
134          * @param builderDelegate delegate that provides the actual implementation.
135          * <p>{@hide}
136          */
Builder(ICronetEngineBuilder builderDelegate)137         public Builder(ICronetEngineBuilder builderDelegate) {
138             if (builderDelegate instanceof ExperimentalOptionsTranslatingCronetEngineBuilder) {
139                 // Already wrapped at the top level, no need to do it again
140                 mBuilderDelegate = builderDelegate;
141             } else {
142                 mBuilderDelegate =
143                         new ExperimentalOptionsTranslatingCronetEngineBuilder(builderDelegate);
144             }
145         }
146 
147         /**
148          * Constructs a User-Agent string including application name and version, system build
149          * version, model and id, and Cronet version.
150          *
151          * @return User-Agent string.
152          */
getDefaultUserAgent()153         public String getDefaultUserAgent() {
154             return mBuilderDelegate.getDefaultUserAgent();
155         }
156 
157         /**
158          * Overrides the User-Agent header for all requests. An explicitly set User-Agent header
159          * (set using {@link UrlRequest.Builder#addHeader}) will override a value set using this
160          * function.
161          *
162          * @param userAgent the User-Agent string to use for all requests.
163          * @return the builder to facilitate chaining.
164          */
setUserAgent(String userAgent)165         public Builder setUserAgent(String userAgent) {
166             mBuilderDelegate.setUserAgent(userAgent);
167             return this;
168         }
169 
170         /**
171          * Sets directory for HTTP Cache and Cookie Storage. The directory must exist.
172          *
173          * <p><b>NOTE:</b> Do not use the same storage directory with more than one {@code
174          * CronetEngine} at a time. Access to the storage directory does not support concurrent
175          * access by multiple {@code CronetEngine}s.
176          *
177          * @param value path to existing directory.
178          * @return the builder to facilitate chaining.
179          */
setStoragePath(String value)180         public Builder setStoragePath(String value) {
181             mBuilderDelegate.setStoragePath(value);
182             return this;
183         }
184 
185         /**
186          * Sets a {@link LibraryLoader} to be used to load the native library. If not set, the
187          * library will be loaded using {@link System#loadLibrary}.
188          *
189          * @param loader {@code LibraryLoader} to be used to load the native library.
190          * @return the builder to facilitate chaining.
191          */
setLibraryLoader(LibraryLoader loader)192         public Builder setLibraryLoader(LibraryLoader loader) {
193             mBuilderDelegate.setLibraryLoader(loader);
194             return this;
195         }
196 
197         /**
198          * Sets whether <a href="https://www.chromium.org/quic">QUIC</a> protocol is enabled.
199          * Defaults to enabled. If QUIC is enabled, then QUIC User Agent Id containing application
200          * name and Cronet version is sent to the server.
201          *
202          * @param value {@code true} to enable QUIC, {@code false} to disable.
203          * @return the builder to facilitate chaining.
204          */
enableQuic(boolean value)205         public Builder enableQuic(boolean value) {
206             mBuilderDelegate.enableQuic(value);
207             return this;
208         }
209 
210         /**
211          * Sets whether <a href="https://tools.ietf.org/html/rfc7540">HTTP/2</a> protocol is
212          * enabled. Defaults to enabled.
213          *
214          * @param value {@code true} to enable HTTP/2, {@code false} to disable.
215          * @return the builder to facilitate chaining.
216          */
enableHttp2(boolean value)217         public Builder enableHttp2(boolean value) {
218             mBuilderDelegate.enableHttp2(value);
219             return this;
220         }
221 
222         /**
223          * @deprecated SDCH is deprecated in Cronet M63. This method is a no-op. {@hide exclude from
224          * JavaDoc}.
225          */
226         @Deprecated
enableSdch(boolean value)227         public Builder enableSdch(boolean value) {
228             return this;
229         }
230 
231         /**
232          * Sets whether <a href="https://tools.ietf.org/html/rfc7932">Brotli</a> compression is
233          * enabled. If enabled, Brotli will be advertised in Accept-Encoding request headers.
234          * Defaults to disabled.
235          *
236          * @param value {@code true} to enable Brotli, {@code false} to disable.
237          * @return the builder to facilitate chaining.
238          */
enableBrotli(boolean value)239         public Builder enableBrotli(boolean value) {
240             mBuilderDelegate.enableBrotli(value);
241             return this;
242         }
243 
244         /**
245          * Setting to disable HTTP cache. Some data may still be temporarily stored in memory.
246          * Passed to
247          * {@link #enableHttpCache}.
248          */
249         public static final int HTTP_CACHE_DISABLED = 0;
250 
251         /**
252          * Setting to enable in-memory HTTP cache, including HTTP data. Passed to {@link
253          * #enableHttpCache}.
254          */
255         public static final int HTTP_CACHE_IN_MEMORY = 1;
256 
257         /**
258          * Setting to enable on-disk cache, excluding HTTP data. {@link #setStoragePath} must be
259          * called prior to passing this constant to {@link #enableHttpCache}.
260          */
261         public static final int HTTP_CACHE_DISK_NO_HTTP = 2;
262 
263         /**
264          * Setting to enable on-disk cache, including HTTP data. {@link #setStoragePath} must be
265          * called prior to passing this constant to {@link #enableHttpCache}.
266          */
267         public static final int HTTP_CACHE_DISK = 3;
268 
269         /**
270          * Enables or disables caching of HTTP data and other information like QUIC server
271          * information.
272          *
273          * @param cacheMode control location and type of cached data. Must be one of {@link
274          * #HTTP_CACHE_DISABLED HTTP_CACHE_*}.
275          * @param maxSize maximum size in bytes used to cache data (advisory and maybe exceeded at
276          * times).
277          * @return the builder to facilitate chaining.
278          */
enableHttpCache(int cacheMode, long maxSize)279         public Builder enableHttpCache(int cacheMode, long maxSize) {
280             mBuilderDelegate.enableHttpCache(cacheMode, maxSize);
281             return this;
282         }
283 
284         /**
285          * Adds hint that {@code host} supports QUIC. Note that {@link #enableHttpCache
286          * enableHttpCache}
287          * ({@link #HTTP_CACHE_DISK}) is needed to take advantage of 0-RTT connection establishment
288          * between sessions.
289          *
290          * @param host hostname of the server that supports QUIC.
291          * @param port host of the server that supports QUIC.
292          * @param alternatePort alternate port to use for QUIC.
293          * @return the builder to facilitate chaining.
294          */
addQuicHint(String host, int port, int alternatePort)295         public Builder addQuicHint(String host, int port, int alternatePort) {
296             mBuilderDelegate.addQuicHint(host, port, alternatePort);
297             return this;
298         }
299 
300         /**
301          * Pins a set of public keys for a given host. By pinning a set of public keys, {@code
302          * pinsSha256}, communication with {@code hostName} is required to authenticate with a
303          * certificate with a public key from the set of pinned ones. An app can pin the public key
304          * of the root certificate, any of the intermediate certificates or the end-entry
305          * certificate. Authentication will fail and secure communication will not be established if
306          * none of the public keys is present in the host's certificate chain, even if the host
307          * attempts to authenticate with a certificate allowed by the device's trusted store of
308          * certificates.
309          *
310          * <p>Calling this method multiple times with the same host name overrides the previously
311          * set pins for the host.
312          *
313          * <p>More information about the public key pinning can be found in <a
314          * href="https://tools.ietf.org/html/rfc7469">RFC 7469</a>.
315          *
316          * @param hostName name of the host to which the public keys should be pinned. A host that
317          * consists only of digits and the dot character is treated as invalid.
318          * @param pinsSha256 a set of pins. Each pin is the SHA-256 cryptographic hash of the
319          * DER-encoded ASN.1 representation of the Subject Public Key Info (SPKI) of the host's
320          * X.509 certificate. Use {@link java.security.cert.Certificate#getPublicKey()
321          * Certificate.getPublicKey()} and {@link java.security.Key#getEncoded() Key.getEncoded()}
322          * to obtain DER-encoded ASN.1 representation of the SPKI. Although, the method does not
323          * mandate the presence of the backup pin that can be used if the control of the primary
324          * private key has been lost, it is highly recommended to supply one.
325          * @param includeSubdomains indicates whether the pinning policy should be applied to
326          *         subdomains
327          * of {@code hostName}.
328          * @param expirationDate specifies the expiration date for the pins.
329          * @return the builder to facilitate chaining.
330          * @throws NullPointerException if any of the input parameters are {@code null}.
331          * @throws IllegalArgumentException if the given host name is invalid or {@code pinsSha256}
332          * contains a byte array that does not represent a valid SHA-256 hash.
333          */
addPublicKeyPins( String hostName, Set<byte[]> pinsSha256, boolean includeSubdomains, Date expirationDate)334         public Builder addPublicKeyPins(
335                 String hostName,
336                 Set<byte[]> pinsSha256,
337                 boolean includeSubdomains,
338                 Date expirationDate) {
339             mBuilderDelegate.addPublicKeyPins(
340                     hostName, pinsSha256, includeSubdomains, expirationDate);
341             return this;
342         }
343 
344         /**
345          * Enables or disables public key pinning bypass for local trust anchors. Disabling the
346          * bypass for local trust anchors is highly discouraged since it may prohibit the app from
347          * communicating with the pinned hosts. E.g., a user may want to send all traffic through an
348          * SSL enabled proxy by changing the device proxy settings and adding the proxy certificate
349          * to the list of local trust anchor. Disabling the bypass will most likely prevent the app
350          * from sending any traffic to the pinned hosts. For more information see 'How does key
351          * pinning interact with local proxies and filters?' at
352          * https://www.chromium.org/Home/chromium-security/security-faq
353          *
354          * @param value {@code true} to enable the bypass, {@code false} to disable.
355          * @return the builder to facilitate chaining.
356          */
enablePublicKeyPinningBypassForLocalTrustAnchors(boolean value)357         public Builder enablePublicKeyPinningBypassForLocalTrustAnchors(boolean value) {
358             mBuilderDelegate.enablePublicKeyPinningBypassForLocalTrustAnchors(value);
359             return this;
360         }
361 
362         /**
363          * Sets the thread priority of Cronet's internal thread.
364          *
365          * @param priority the thread priority of Cronet's internal thread. A Linux priority level,
366          *         from
367          * -20 for highest scheduling priority to 19 for lowest scheduling priority. For more
368          * information on values, see {@link android.os.Process#setThreadPriority(int, int)} and
369          * {@link android.os.Process#THREAD_PRIORITY_DEFAULT THREAD_PRIORITY_*} values.
370          * @return the builder to facilitate chaining.
371          */
setThreadPriority(int priority)372         public Builder setThreadPriority(int priority) {
373             mBuilderDelegate.setThreadPriority(priority);
374             return this;
375         }
376 
377         /**
378          * Enables the network quality estimator, which collects and reports measurements of round
379          * trip time (RTT) and downstream throughput at various layers of the network stack. After
380          * enabling the estimator, listeners of RTT and throughput can be added with {@link
381          * #addRttListener} and
382          * {@link #addThroughputListener} and removed with {@link #removeRttListener} and {@link
383          * #removeThroughputListener}. The estimator uses memory and CPU only when enabled.
384          *
385          * @param value {@code true} to enable network quality estimator, {@code false} to disable.
386          * @return the builder to facilitate chaining.
387          */
enableNetworkQualityEstimator(boolean value)388         public Builder enableNetworkQualityEstimator(boolean value) {
389             mBuilderDelegate.enableNetworkQualityEstimator(value);
390             return this;
391         }
392 
393         /**
394          * Configures the behavior of Cronet when using QUIC. For more details, see documentation
395          * of {@link QuicOptions} and the individual methods of {@link QuicOptions.Builder}.
396          *
397          * <p>Only relevant if {@link #enableQuic(boolean)} is enabled.
398          *
399          * @return the builder to facilitate chaining.
400          */
401         @QuicOptions.Experimental
setQuicOptions(QuicOptions quicOptions)402         public Builder setQuicOptions(QuicOptions quicOptions) {
403             mBuilderDelegate.setQuicOptions(quicOptions);
404             return this;
405         }
406 
407         /** @see #setQuicOptions(QuicOptions) */
408         @QuicOptions.Experimental
setQuicOptions(QuicOptions.Builder quicOptionsBuilder)409         public Builder setQuicOptions(QuicOptions.Builder quicOptionsBuilder) {
410             return setQuicOptions(quicOptionsBuilder.build());
411         }
412 
413         /**
414          * Configures the behavior of hostname lookup. For more details, see documentation
415          * of {@link DnsOptions} and the individual methods of {@link DnsOptions.Builder}.
416          *
417          * <p>Only relevant if {@link #enableQuic(boolean)} is enabled.
418          *
419          * @return the builder to facilitate chaining.
420          */
421         @DnsOptions.Experimental
setDnsOptions(DnsOptions dnsOptions)422         public Builder setDnsOptions(DnsOptions dnsOptions) {
423             mBuilderDelegate.setDnsOptions(dnsOptions);
424             return this;
425         }
426 
427         /** @see #setDnsOptions(DnsOptions) */
428         @DnsOptions.Experimental
setDnsOptions(DnsOptions.Builder dnsOptions)429         public Builder setDnsOptions(DnsOptions.Builder dnsOptions) {
430             return setDnsOptions(dnsOptions.build());
431         }
432 
433         /**
434          * Configures the behavior of connection migration. For more details, see documentation
435          * of {@link ConnectionMigrationOptions} and the individual methods of {@link
436          * ConnectionMigrationOptions.Builder}.
437          *
438          * <p>Only relevant if {@link #enableQuic(boolean)} is enabled.
439          *
440          * @return the builder to facilitate chaining.
441          */
442         @ConnectionMigrationOptions.Experimental
setConnectionMigrationOptions( ConnectionMigrationOptions connectionMigrationOptions)443         public Builder setConnectionMigrationOptions(
444                 ConnectionMigrationOptions connectionMigrationOptions) {
445             mBuilderDelegate.setConnectionMigrationOptions(connectionMigrationOptions);
446             return this;
447         }
448 
449         /** @see #setConnectionMigrationOptions(ConnectionMigrationOptions) */
450         @ConnectionMigrationOptions.Experimental
setConnectionMigrationOptions( ConnectionMigrationOptions.Builder connectionMigrationOptionsBuilder)451         public Builder setConnectionMigrationOptions(
452                 ConnectionMigrationOptions.Builder connectionMigrationOptionsBuilder) {
453             return setConnectionMigrationOptions(connectionMigrationOptionsBuilder.build());
454         }
455 
456         /**
457          * Build a {@link CronetEngine} using this builder's configuration.
458          *
459          * @return constructed {@link CronetEngine}.
460          */
build()461         public CronetEngine build() {
462             int implLevel = getImplementationApiLevel();
463             if (implLevel != -1 && implLevel < getMaximumApiLevel()) {
464                 Log.w(
465                         TAG,
466                         "The implementation version is lower than the API version. Calls to "
467                                 + "methods added in API "
468                                 + (implLevel + 1)
469                                 + " and newer will "
470                                 + "likely have no effect.");
471             }
472 
473             return mBuilderDelegate.build();
474         }
475 
476         /**
477          * Creates an implementation of {@link ICronetEngineBuilder} that can be used to delegate
478          * the builder calls to. The method uses {@link CronetProvider} to obtain the list of
479          * available providers.
480          *
481          * @param context Android Context to use.
482          * @return the created {@code ICronetEngineBuilder}.
483          */
createBuilderDelegate(Context context)484         private static ICronetEngineBuilder createBuilderDelegate(Context context) {
485             List<CronetProvider> providers =
486                     new ArrayList<>(CronetProvider.getAllProviders(context));
487             CronetProvider provider = getEnabledCronetProviders(context, providers).get(0);
488             if (Log.isLoggable(TAG, Log.DEBUG)) {
489                 Log.d(
490                         TAG,
491                         String.format(
492                                 "Using '%s' provider for creating CronetEngine.Builder.",
493                                 provider));
494             }
495             return provider.createBuilder().mBuilderDelegate;
496         }
497 
498         /**
499          * Returns the list of available and enabled {@link CronetProvider}. The returned list is
500          * sorted based on the provider versions and types.
501          *
502          * @param context Android Context to use.
503          * @param providers the list of enabled and disabled providers to filter out and sort.
504          * @return the sorted list of enabled providers. The list contains at least one provider.
505          * @throws RuntimeException is the list of providers is empty or all of the providers are
506          * disabled.
507          */
508         @VisibleForTesting
getEnabledCronetProviders( Context context, List<CronetProvider> providers)509         static List<CronetProvider> getEnabledCronetProviders(
510                 Context context, List<CronetProvider> providers) {
511             // Check that there is at least one available provider.
512             if (providers.isEmpty()) {
513                 throw new RuntimeException(
514                         "Unable to find any Cronet provider."
515                                 + " Have you included all necessary jars?");
516             }
517 
518             // Exclude disabled providers from the list.
519             for (Iterator<CronetProvider> i = providers.iterator(); i.hasNext(); ) {
520                 CronetProvider provider = i.next();
521                 if (!provider.isEnabled()) {
522                     i.remove();
523                 }
524             }
525 
526             // Check that there is at least one enabled provider.
527             if (providers.isEmpty()) {
528                 throw new RuntimeException(
529                         "All available Cronet providers are disabled."
530                                 + " A provider should be enabled before it can be used.");
531             }
532 
533             // Sort providers based on version and type.
534             Collections.sort(
535                     providers,
536                     new Comparator<CronetProvider>() {
537                         @Override
538                         public int compare(CronetProvider p1, CronetProvider p2) {
539                             // The fallback provider should always be at the end of the list.
540                             if (CronetProvider.PROVIDER_NAME_FALLBACK.equals(p1.getName())) {
541                                 return 1;
542                             }
543                             if (CronetProvider.PROVIDER_NAME_FALLBACK.equals(p2.getName())) {
544                                 return -1;
545                             }
546                             // A provider with higher version should go first.
547                             return -compareVersions(p1.getVersion(), p2.getVersion());
548                         }
549                     });
550             return providers;
551         }
552 
553         /**
554          * Compares two strings that contain versions. The string should only contain dot-separated
555          * segments that contain an arbitrary number of digits digits [0-9].
556          *
557          * @param s1 the first string.
558          * @param s2 the second string.
559          * @return -1 if s1<s2, +1 if s1>s2 and 0 if s1=s2. If two versions are equal, the version
560          *         with
561          * the higher number of segments is considered to be higher.
562          * @throws IllegalArgumentException if any of the strings contains an illegal version
563          *         number.
564          */
565         @VisibleForTesting
compareVersions(String s1, String s2)566         static int compareVersions(String s1, String s2) {
567             if (s1 == null || s2 == null) {
568                 throw new IllegalArgumentException("The input values cannot be null");
569             }
570             String[] s1segments = s1.split("\\.");
571             String[] s2segments = s2.split("\\.");
572             for (int i = 0; i < s1segments.length && i < s2segments.length; i++) {
573                 try {
574                     int s1segment = Integer.parseInt(s1segments[i]);
575                     int s2segment = Integer.parseInt(s2segments[i]);
576                     if (s1segment != s2segment) {
577                         return Integer.signum(s1segment - s2segment);
578                     }
579                 } catch (NumberFormatException e) {
580                     throw new IllegalArgumentException(
581                             "Unable to convert version segments into"
582                                     + " integers: "
583                                     + s1segments[i]
584                                     + " & "
585                                     + s2segments[i],
586                             e);
587                 }
588             }
589             return Integer.signum(s1segments.length - s2segments.length);
590         }
591 
getMaximumApiLevel()592         private int getMaximumApiLevel() {
593             return ApiVersion.getMaximumAvailableApiLevel();
594         }
595 
596         /**
597          * Returns the implementation version, the implementation being represented by the delegate
598          * builder, or {@code -1} if the version couldn't be retrieved.
599          */
getImplementationApiLevel()600         private int getImplementationApiLevel() {
601             try {
602                 ClassLoader implClassLoader = mBuilderDelegate.getClass().getClassLoader();
603                 Class<?> implVersionClass =
604                         implClassLoader.loadClass("org.chromium.net.impl.ImplVersion");
605                 Method getApiLevel = implVersionClass.getMethod("getApiLevel");
606                 int implementationApiLevel = (Integer) getApiLevel.invoke(null);
607 
608                 return implementationApiLevel;
609             } catch (Exception e) {
610                 // Any exception in the block above isn't critical, don't bother the app about it.
611                 return -1;
612             }
613         }
614     }
615 
616     /** @return a human-readable version string of the engine. */
getVersionString()617     public abstract String getVersionString();
618 
619     /**
620      * Shuts down the {@link CronetEngine} if there are no active requests, otherwise throws an
621      * exception.
622      *
623      * <p>Cannot be called on network thread - the thread Cronet calls into Executor on (which is
624      * different from the thread the Executor invokes callbacks on). May block until all the {@code
625      * CronetEngine}'s resources have been cleaned up.
626      */
shutdown()627     public abstract void shutdown();
628 
629     /**
630      * Starts NetLog logging to a file. The NetLog will contain events emitted by all live
631      * CronetEngines. The NetLog is useful for debugging. The file can be viewed using a Chrome
632      * browser navigated to chrome://net-internals/#import
633      *
634      * @param fileName the complete file path. It must not be empty. If the file exists, it is
635      * truncated before starting. If actively logging, this method is ignored.
636      * @param logAll {@code true} to include basic events, user cookies, credentials and all
637      * transferred bytes in the log. This option presents a privacy risk, since it exposes the
638      * user's credentials, and should only be used with the user's consent and in situations where
639      * the log won't be public. {@code false} to just include basic events.
640      */
startNetLogToFile(String fileName, boolean logAll)641     public abstract void startNetLogToFile(String fileName, boolean logAll);
642 
643     /**
644      * Stops NetLog logging and flushes file to disk. If a logging session is not in progress, this
645      * call is ignored.
646      */
stopNetLog()647     public abstract void stopNetLog();
648 
649     /**
650      * Returns differences in metrics collected by Cronet since the last call to this method.
651      *
652      * <p>Cronet collects these metrics globally. This means deltas returned by {@code
653      * getGlobalMetricsDeltas()} will include measurements of requests processed by other {@link
654      * CronetEngine} instances. Since this function returns differences in metrics collected since
655      * the last call, and these metrics are collected globally, a call to any {@code CronetEngine}
656      * instance's {@code getGlobalMetricsDeltas()} method will affect the deltas returned by any
657      * other
658      * {@code CronetEngine} instance's {@code getGlobalMetricsDeltas()}.
659      *
660      * <p>Cronet starts collecting these metrics after the first call to {@code
661      * getGlobalMetricsDeltras()}, so the first call returns no useful data as no metrics have yet
662      * been collected.
663      *
664      * @return differences in metrics collected by Cronet, since the last call to {@code
665      * getGlobalMetricsDeltas()}, serialized as a <a
666      * href=https://developers.google.com/protocol-buffers>protobuf
667      * </a>.
668      */
getGlobalMetricsDeltas()669     public abstract byte[] getGlobalMetricsDeltas();
670 
671     /**
672      * Establishes a new connection to the resource specified by the {@link URL} {@code url}.
673      *
674      * <p><b>Note:</b> Cronet's {@link java.net.HttpURLConnection} implementation is subject to
675      * certain limitations, see {@link #createURLStreamHandlerFactory} for details.
676      *
677      * @param url URL of resource to connect to.
678      * @return an {@link java.net.HttpURLConnection} instance implemented by this CronetEngine.
679      * @throws IOException if an error occurs while opening the connection.
680      */
openConnection(URL url)681     public abstract URLConnection openConnection(URL url) throws IOException;
682 
683     /**
684      * Creates a {@link URLStreamHandlerFactory} to handle HTTP and HTTPS traffic. An instance of
685      * this class can be installed via {@link URL#setURLStreamHandlerFactory} thus using this
686      * CronetEngine by default for all requests created via {@link URL#openConnection}.
687      *
688      * <p>Cronet does not use certain HTTP features provided via the system:
689      *
690      * <ul>
691      *   <li>the HTTP cache installed via {@link HttpResponseCache#install(java.io.File, long)
692      *       HttpResponseCache.install()}
693      *   <li>the HTTP authentication method installed via {@link java.net.Authenticator#setDefault}
694      *   <li>the HTTP cookie storage installed via {@link java.net.CookieHandler#setDefault}
695      * </ul>
696      *
697      * <p>While Cronet supports and encourages requests using the HTTPS protocol, Cronet does not
698      * provide support for the {@link HttpsURLConnection} API. This lack of support also includes
699      * not using certain HTTPS features provided via the system:
700      *
701      * <ul>
702      *   <li>the HTTPS hostname verifier installed via {@link
703      *       HttpsURLConnection#setDefaultHostnameVerifier(javax.net.ssl.HostnameVerifier)
704      *       HttpsURLConnection.setDefaultHostnameVerifier()}
705      *   <li>the HTTPS socket factory installed via {@link
706      *       HttpsURLConnection#setDefaultSSLSocketFactory(javax.net.ssl.SSLSocketFactory)
707      *       HttpsURLConnection.setDefaultSSLSocketFactory()}
708      * </ul>
709      *
710      * @return an {@link URLStreamHandlerFactory} instance implemented by this CronetEngine.
711      */
createURLStreamHandlerFactory()712     public abstract URLStreamHandlerFactory createURLStreamHandlerFactory();
713 
714     /**
715      * Creates a builder for {@link UrlRequest}. All callbacks for generated {@link UrlRequest}
716      * objects will be invoked on {@code executor}'s threads. {@code executor} must not run tasks on
717      * the thread calling {@link Executor#execute} to prevent blocking networking operations and
718      * causing exceptions during shutdown.
719      *
720      * @param url URL for the generated requests.
721      * @param callback callback object that gets invoked on different events.
722      * @param executor {@link Executor} on which all callbacks will be invoked.
723      */
newUrlRequestBuilder( String url, UrlRequest.Callback callback, Executor executor)724     public abstract UrlRequest.Builder newUrlRequestBuilder(
725             String url, UrlRequest.Callback callback, Executor executor);
726 
727     /**
728      * Creates a builder for {@link BidirectionalStream} objects. All callbacks for generated {@code
729      * BidirectionalStream} objects will be invoked on {@code executor}. {@code executor} must not
730      * run tasks on the current thread, otherwise the networking operations may block and exceptions
731      * may be thrown at shutdown time.
732      *
733      * @param url URL for the generated streams.
734      * @param callback the {@link BidirectionalStream.Callback} object that gets invoked upon
735      * different events occurring.
736      * @param executor the {@link Executor} on which {@code callback} methods will be invoked.
737      * @return the created builder.
738      *
739      * {@hide}
740      */
newBidirectionalStreamBuilder( String url, BidirectionalStream.Callback callback, Executor executor)741     public BidirectionalStream.Builder newBidirectionalStreamBuilder(
742             String url, BidirectionalStream.Callback callback, Executor executor) {
743         throw new UnsupportedOperationException("Not implemented.");
744     }
745 
746     /**
747      * Returns the number of active requests.
748      * <p>
749      * A request becomes "active" in UrlRequest.start(), assuming that method
750      * does not throw an exception. It becomes inactive when all callbacks have
751      * returned and no additional callbacks can be triggered in the future. In
752      * practice, that means the request is inactive once
753      * onSucceeded/onCanceled/onFailed has returned and all request finished
754      * listeners have returned.
755      *
756      * <a href="https://developer.android.com/guide/topics/connectivity/cronet/lifecycle">Cronet
757      *         requests's lifecycle</a> for more information.
758      */
getActiveRequestCount()759     public int getActiveRequestCount() {
760         return ACTIVE_REQUEST_COUNT_UNKNOWN;
761     }
762 
763     /**
764      * Registers a listener that gets called after the end of each request with the request info.
765      *
766      * <p>The listener is called on an {@link java.util.concurrent.Executor} provided by the
767      * listener.
768      *
769      * @param listener the listener for finished requests.
770      */
addRequestFinishedListener(RequestFinishedInfo.Listener listener)771     public void addRequestFinishedListener(RequestFinishedInfo.Listener listener) {}
772 
773     /**
774      * Removes a finished request listener.
775      *
776      * @param listener the listener to remove.
777      */
removeRequestFinishedListener(RequestFinishedInfo.Listener listener)778     public void removeRequestFinishedListener(RequestFinishedInfo.Listener listener) {}
779 
780     /**
781      * Returns the HTTP RTT estimate (in milliseconds) computed by the network quality estimator.
782      * Set to {@link #CONNECTION_METRIC_UNKNOWN} if the value is unavailable. This must be called
783      * after
784      * {@link Builder#enableNetworkQualityEstimator}, and will throw an exception otherwise.
785      *
786      * @return Estimate of the HTTP RTT in milliseconds.
787      */
getHttpRttMs()788     public int getHttpRttMs() {
789         return CONNECTION_METRIC_UNKNOWN;
790     }
791 
792     /**
793      * Returns the transport RTT estimate (in milliseconds) computed by the network quality
794      * estimator. Set to {@link #CONNECTION_METRIC_UNKNOWN} if the value is unavailable. This must
795      * be called after {@link Builder#enableNetworkQualityEstimator}, and will throw an exception
796      * otherwise.
797      *
798      * @return Estimate of the transport RTT in milliseconds.
799      */
getTransportRttMs()800     public int getTransportRttMs() {
801         return CONNECTION_METRIC_UNKNOWN;
802     }
803 
804     /**
805      * Returns the downstream throughput estimate (in kilobits per second) computed by the network
806      * quality estimator. Set to {@link #CONNECTION_METRIC_UNKNOWN} if the value is unavailable.
807      * This must be called after {@link Builder#enableNetworkQualityEstimator}, and will throw an
808      * exception otherwise.
809      *
810      * @return Estimate of the downstream throughput in kilobits per second.
811      */
getDownstreamThroughputKbps()812     public int getDownstreamThroughputKbps() {
813         return CONNECTION_METRIC_UNKNOWN;
814     }
815 
816     /**
817      * Starts NetLog logging to a specified directory with a bounded size. The NetLog will contain
818      * events emitted by all live CronetEngines. The NetLog is useful for debugging. Once logging
819      * has stopped {@link #stopNetLog}, the data will be written to netlog.json in {@code dirPath}.
820      * If logging is interrupted, you can stitch the files found in .inprogress subdirectory
821      * manually using:
822      * https://chromium.googlesource.com/chromium/src/+/main/net/tools/stitch_net_log_files.py. The
823      * log can be viewed using a Chrome browser navigated to chrome://net-internals/#import.
824      *
825      * @param dirPath the directory where the netlog.json file will be created. dirPath must already
826      * exist. NetLog files must not exist in the directory. If actively logging, this method is
827      * ignored.
828      * @param logAll {@code true} to include basic events, user cookies, credentials and all
829      * transferred bytes in the log. This option presents a privacy risk, since it exposes the
830      * user's credentials, and should only be used with the user's consent and in situations where
831      * the log won't be public. {@code false} to just include basic events.
832      * @param maxSize the maximum total disk space in bytes that should be used by NetLog. Actual
833      *         disk
834      * space usage may exceed this limit slightly.
835      */
startNetLogToDisk(String dirPath, boolean logAll, int maxSize)836     public void startNetLogToDisk(String dirPath, boolean logAll, int maxSize) {}
837 
838     /**
839      * Binds the engine to the specified network handle. All requests created through this engine
840      * will use the network associated to this handle. If this network disconnects all requests will
841      * fail, the exact error will depend on the stage of request processing when the network
842      * disconnects. Network handles can be obtained through {@code Network#getNetworkHandle}. Only
843      * available starting from Android Marshmallow.
844      *
845      * @param networkHandle the network handle to bind the engine to. Specify {@link
846      * #UNBIND_NETWORK_HANDLE} to unbind.
847      */
bindToNetwork(long networkHandle)848     public void bindToNetwork(long networkHandle) {}
849 
850     /**
851      * Returns an estimate of the effective connection type computed by the network quality
852      * estimator. Call {@link Builder#enableNetworkQualityEstimator} to begin computing this value.
853      *
854      * @return the estimated connection type. The returned value is one of {@link
855      * #EFFECTIVE_CONNECTION_TYPE_UNKNOWN EFFECTIVE_CONNECTION_TYPE_* }.
856      */
getEffectiveConnectionType()857     public int getEffectiveConnectionType() {
858         return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
859     }
860 
861     /**
862      * Configures the network quality estimator for testing. This must be called before round trip
863      * time and throughput listeners are added, and after the network quality estimator has been
864      * enabled.
865      *
866      * @param useLocalHostRequests include requests to localhost in estimates.
867      * @param useSmallerResponses include small responses in throughput estimates.
868      * @param disableOfflineCheck when set to true, disables the device offline checks when
869      *         computing
870      * the effective connection type or when writing the prefs.
871      */
configureNetworkQualityEstimatorForTesting( boolean useLocalHostRequests, boolean useSmallerResponses, boolean disableOfflineCheck)872     public void configureNetworkQualityEstimatorForTesting(
873             boolean useLocalHostRequests,
874             boolean useSmallerResponses,
875             boolean disableOfflineCheck) {}
876 
877     /**
878      * Registers a listener that gets called whenever the network quality estimator witnesses a
879      * sample round trip time. This must be called after {@link
880      * Builder#enableNetworkQualityEstimator}, and with throw an exception otherwise. Round trip
881      * times may be recorded at various layers of the network stack, including TCP, QUIC, and at the
882      * URL request layer. The listener is called on the
883      * {@link java.util.concurrent.Executor} that is passed to {@link
884      * Builder#enableNetworkQualityEstimator}.
885      *
886      * @param listener the listener of round trip times.
887      */
addRttListener(NetworkQualityRttListener listener)888     public void addRttListener(NetworkQualityRttListener listener) {}
889 
890     /**
891      * Removes a listener of round trip times if previously registered with {@link #addRttListener}.
892      * This should be called after a {@link NetworkQualityRttListener} is added in order to stop
893      * receiving observations.
894      *
895      * @param listener the listener of round trip times.
896      */
removeRttListener(NetworkQualityRttListener listener)897     public void removeRttListener(NetworkQualityRttListener listener) {}
898 
899     /**
900      * Registers a listener that gets called whenever the network quality estimator witnesses a
901      * sample throughput measurement. This must be called after {@link
902      * Builder#enableNetworkQualityEstimator}. Throughput observations are computed by measuring
903      * bytes read over the active network interface at times when at least one URL response is being
904      * received. The listener is called on the {@link java.util.concurrent.Executor} that is passed
905      * to {@link Builder#enableNetworkQualityEstimator}.
906      *
907      * @param listener the listener of throughput.
908      */
addThroughputListener(NetworkQualityThroughputListener listener)909     public void addThroughputListener(NetworkQualityThroughputListener listener) {}
910 
911     /**
912      * Removes a listener of throughput. This should be called after a {@link
913      * NetworkQualityThroughputListener} is added with {@link #addThroughputListener} in order to
914      * stop receiving observations.
915      *
916      * @param listener the listener of throughput.
917      */
removeThroughputListener(NetworkQualityThroughputListener listener)918     public void removeThroughputListener(NetworkQualityThroughputListener listener) {}
919 }
920