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