1/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17syntax = "proto2";
18
19package android.os.statsd.cronet;
20
21import "frameworks/proto_logging/stats/atoms.proto";
22import "frameworks/proto_logging/stats/atom_field_options.proto";
23
24option java_package = "com.android.os.cronet";
25option java_multiple_files = true;
26
27extend Atom {
28  optional CronetEngineCreated cronet_engine_created = 703
29  [(module) = "cronet"];
30  optional CronetTrafficReported cronet_traffic_reported = 704
31  [(module) = "cronet"];
32  optional CronetEngineBuilderInitialized cronet_engine_builder_initialized = 762 [(module) = "cronet"];
33  optional CronetHttpFlagsInitialized cronet_http_flags_initialized = 763 [(module) = "cronet"];
34  optional CronetInitialized cronet_initialized = 764 [(module) = "cronet"];
35}
36
37// Logged every time CronetEngine.Builder#build() returns.
38message CronetEngineCreated {
39  // A weak-ID-like reference to the instance of the Cronet engine being
40  // created. The field can be used to join subsequent request metrics with the
41  // engine details.
42  //
43  // The reference is NOT meant to be globally (or even on-device) unique, but
44  // on device collisions should be unlikely.
45  // Defaults to max positive int64 value which is equivalent to "not set".
46  optional int64 engine_instance_ref = 1 [default = 9223372036854775807];
47  // Deprecated, moved to CronetEngineBuilderInitialized
48  optional int32 major_version = 2 [deprecated = true];
49  // Deprecated, moved to CronetEngineBuilderInitialized
50  optional int32 minor_version = 3 [deprecated = true];
51  // Deprecated, moved to CronetEngineBuilderInitialized
52  optional int32 build_version = 4 [deprecated = true];
53  // Deprecated, moved to CronetEngineBuilderInitialized
54  optional int32 patch_version = 5 [deprecated = true];
55
56  // Deprecated, moved to CronetInitialized
57  optional CronetSource source = 6 [deprecated = true];
58  // Options that can be set on the Cronet builder. Only fields which are
59  // actively set by the Cronet user are populated. When using the protos
60  // default values should be considered as "null" - default semnantics can
61  // change based on the Cronet version.
62  //
63  // Fields that can contain free text (even if just theoretically) should be
64  // curated and/or replaced with fields that provide useful signal while not
65  // being sensitive. For instance, instead of logging values of quic hint hosts
66  // verbatim, prefer to log if a request was affected by a hint.
67  //
68  // For field names, follow the nomenclature below:
69  // - fields set directly on the builder should have no prefix
70  //   (e.g., enableBrotli() translates to enable_brotli)
71  // - fields which are set in a sub-object or sub-structure should be prefixed
72  //   with the path leading to that field. For example,
73  //   builder.setExperimentalOptions("quic: { foo: { bar: 2 } }");
74  //   translates to experimental_options_quic_foo_bar
75  //
76  //
77  // In both cases, keep the existing names that are used in Cronet if at all
78  // possible.
79
80  // --- CronetEngine.Builder controls ---
81  optional bool enable_brotli = 7;
82  optional bool enable_http2 = 8;
83  optional CronetHttpCacheMode http_cache_mode = 9;
84  optional bool enable_public_key_pinning_bypass_for_local_trust_anchors = 10;
85  optional bool enable_quic = 11;
86
87  // --- ExperimentalCronetEngine.Builder controls ---
88  optional bool enable_network_quality_estimator = 12;
89  optional int32 thread_priority = 13;
90
91  // --- JSON experimental options ---
92  // The JSON config offers a lot of options but most of the atoms will have
93  // a majority of the fields below unset. We considered lumping the boolean
94  // flags into a single int32 field bud decided not to do so because
95  //   a) having the standalone booleans makes the data set easier to understand
96  //      and use
97  //   b) we need to distinguish between three states (unset / true / false)
98  //      which makes the compaction less efficient
99  //   c) we expect the booleans to not be set in majority of the cases,
100  //      in such a case, no space is saved.
101
102  // QUIC
103  // Lexicographically sorted, comma separated, curated list of QUIC connection
104  // options.
105  optional string experimental_options_quic_connection_options = 14;
106  optional OptionalBoolean
107      experimental_options_quic_store_server_configs_in_properties = 15;
108  // Unset value is -1
109  optional int32
110      experimental_options_quic_max_server_configs_stored_in_properties = 16
111      [default = -1];
112  // Unset value is -1
113  optional int32 experimental_options_quic_idle_connection_timeout_seconds = 17
114      [default = -1];
115  optional OptionalBoolean
116      experimental_options_quic_goaway_sessions_on_ip_change = 18;
117  optional OptionalBoolean
118      experimental_options_quic_close_sessions_on_ip_change = 19;
119  optional OptionalBoolean
120      experimental_options_quic_migrate_sessions_on_network_change_v2 = 20;
121  optional OptionalBoolean experimental_options_quic_migrate_sessions_early_v2 =
122      21;
123  optional OptionalBoolean
124      experimental_options_quic_quic_disable_bidirectional_streams = 22;
125  // Unset value is -1
126  optional int32
127      experimental_options_quic_max_time_before_crypto_handshake_seconds = 23
128      [default = -1];
129  // Unset value is -1
130  optional int32
131      experimental_options_quic_max_idle_time_before_crypto_handshake_seconds =
132          24 [default = -1];
133  optional OptionalBoolean
134      experimental_options_quic_enable_socket_recv_optimization = 25;
135
136  // DNS
137  optional OptionalBoolean experimental_options_asyncdns_enable = 26;
138  optional OptionalBoolean experimental_options_staledns_enable = 27;
139  // Unset value is -1
140  optional int32 experimental_options_staledns_delay_ms = 28 [default = -1];
141  // Unset value is -1
142  optional int32 experimental_options_staledns_max_expired_time_ms = 29
143  [default = -1];
144  // Unset value is -1
145  optional int32 experimental_options_staledns_max_stale_uses = 30
146  [default = -1];
147  optional OptionalBoolean experimental_options_staledns_allow_other_network =
148      31;
149  optional OptionalBoolean experimental_options_staledns_persist_to_disk = 32;
150  // Unset value is -1
151  optional int32 experimental_options_staledns_persist_delay_ms = 33
152  [default = -1];
153  optional OptionalBoolean
154      experimental_options_staledns_use_stale_on_name_not_resolved = 34;
155  // Host resolver rules omitted
156  optional OptionalBoolean experimental_options_disable_ipv6_on_wifi = 35;
157
158  // Deprecated, moved to CronetEngineBuilderInitialized.
159  enum CronetSource {
160    option deprecated = true;
161    // Safe default, don't use explicitly.
162    CRONET_SOURCE_UNSPECIFIED = 0;
163    // The library is bundled with the application.
164    CRONET_SOURCE_STATICALLY_LINKED = 1;
165    // The library is loaded from GMS Core
166    CRONET_SOURCE_GMSCORE_DYNAMITE = 2;
167    // The application is using the fallback implementation
168    CRONET_SOURCE_FALLBACK = 3;
169  }
170
171  // A pointer to CronetInitialized.cronet_initialization_ref for the Cronet initialization
172  // sequence that this engine relied on.
173  // Note that CronetInitialized may be logged after CronetEngineCreated because initialization
174  // continues in the background after the CronetEngine is instantiated.
175  // One consequence is that this reference can be broken if a
176  // crash occurs after the engine is created but before initialization is complete.
177  optional int64 cronet_initialization_ref = 36;
178
179  // See
180  // https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/CronetEngine.Builder.html#constants
181  // for detailed semantics.
182  enum CronetHttpCacheMode {
183    // Safe default, don't use explicitly.
184    HTTP_CACHE_MODE_UNSPECIFIED = 0;
185
186    HTTP_CACHE_DISABLED = 1;
187    HTTP_CACHE_DISK = 2;
188    HTTP_CACHE_DISK_NO_HTTP = 3;
189    HTTP_CACHE_IN_MEMORY = 4;
190  }
191}
192
193// Logged when a request has reached terminal state after the final user callback has returned
194// and before the requestFinishedListeners has fired.
195message CronetTrafficReported {
196  // The Cronet engine that sent the trafic. See
197  // CronetEngineCreated.engine_instance_ref for more details.
198  // Defaults to max negative int64 value which is equivalent to "not set".
199  // The default value is deliberately different from
200  // CronetEngineCreated.engine_instance_ref to avoid unintentional joining.
201  optional int64 engine_instance_ref = 1 [default = -9223372036854775808];
202
203  // Bucketized sizes for request and response headers and body.
204  optional CronetRequestHeadersSizeBucket request_headers_size = 2;
205  optional CronetRequestBodySizeBucket request_body_size = 3;
206  optional CronetResponseHeadersSizeBucket response_headers_size = 4;
207  optional CronetResponseBodySizeBucket response_body_size = 5;
208
209  // The status code of the response.
210  optional int32 http_status_code = 6;
211  // The Fingerprint2011 hash of the protocol that was negotiated for this
212  // request (as returned by UrlResponseInfo.getNegotiatedProtocol()). The
213  // possible values for the string are limited so the hash is sufficient
214  // to identify known values while preventing accidental presence of
215  // freeform text.
216  // See go/cronet-negotiated-protocols for possible values.
217  optional int64 negotiated_protocol_hash = 7;
218
219  // The time it took from starting the request to receiving the full set of
220  // response headers, in milliseconds.
221  optional int32 headers_latency_millis = 8;
222
223  // The time that elapsed from the point UrlRequest#start() was called to the point
224  // we are ready to call the final user callback (e.g. onSucceeded).
225  // Note: this includes time spent waiting for the user to issue an I/O request.
226  // In other words this includes the effect of the user
227  // throttling Cronet (a.k.a. flow control, a.k.a. backpressure).
228  // See also total_idle_time_millis
229  optional int32 overall_latency_millis = 9;
230
231  // Whether a connection migration was attempted for this request.
232  optional bool connection_migration_attempted = 10;
233  // Whether a connection migration was attempted and successful for this
234  // request.
235  optional bool connection_migration_successful = 11;
236
237  // Number of previous CronetTrafficReported records that were dropped due to rate limiting.
238  optional int32 samples_rate_limited = 12;
239
240  // Terminal state of the reported request.
241  optional CronetRequestTerminalState terminal_state = 13;
242
243  enum CronetRequestTerminalState {
244    STATE_UNKNOWN = 0;
245    STATE_SUCCEEDED = 1;
246    STATE_ERROR = 2;
247    STATE_CANCELLED = 3;
248  }
249
250  // count of exceptions thrown during the execution of a user callback.
251  optional int32 user_callback_exception_count = 14;
252
253  // Same as `overall_latency_millis`, but only including time spent with no
254  // outstanding I/O request from the user. For example, the time that elapses between Cronet
255  // becoming ready to call the onReadCompleted callback and the user making the
256  // next UrlRequest#read() call is idle time: during that time
257  // there is no outstanding read request.
258  // If this value is large relative to overall_latency_millis, it may mean the request was
259  // throttled by the user, i.e. they applied backpressure/flow control, intentionally or not.
260  // Note that in this context, "idle" should be interpreted from the
261  // perspective of the Cronet user. Internally, Cronet might not actually be "idle"
262  // as it may still attempt to keep its internal buffers filled.
263  // An example of Cronet idly waiting for the user would look like the following
264  /*
265              Cronet                          User
266                |
267                |
268                |----- OnResponseStarted ------|
269                                               |
270     Cronet                                    |
271     Idle                                      |
272     Time                                      |
273                                               |
274Cronet          |------------------------------| User calls request.read()
275Doing           |
276Work            |
277                |
278OnReadCompleted |
279                |
280                |----- onReadCompleted -------|
281                                              | Cronet Idle Time includes the time taken to call
282                                              | Executor#execute() on the user's executor.
283                                              |
284      Cronet                                  | If the user is blocking the network
285      Idle                                    | thread in Executor#execute(), then technically that
286      Time                                    | counts as backpressure / flow control.
287                                              |
288                                              |
289                                              |
290                                              |
291                                              |
292                                              |
293                                              |
294                                              |
295                                              |
296                                              |
297               |------------------------------|
298   */
299  // This field contains the sum of Cronet Idle time waiting for user calls.
300  optional int64 total_idle_time_millis = 15;
301
302  // The time it takes for the user's Executor#execute() method to return
303  // Note: contrary to most other metrics in this atom, this also includes
304  // the final user callback (e.g. onSucceeded).
305  // Note: in the case of the native implementation, Executor#execute() is called on
306  // the network thread, which is a shared resource. High values for this metric are
307  // usually a red flag because they mean the network thread is unable to service any
308  // other UrlRequests during this time (including those from other engines).
309  optional int64 total_user_executor_execute_latency_millis = 16;
310
311  // The total amount of times `UrlRequest#read()` was called.
312  optional int32 read_count = 17;
313
314  // The total amount of times `UploadDataProvider#read` has been fired.
315  optional int32 on_upload_read_count = 18;
316
317  // Indicates if the request is a bidirectional stream or not.
318  optional OptionalBoolean is_bidi_stream = 19;
319
320
321  enum CronetRequestHeadersSizeBucket {
322    REQUEST_HEADERS_SIZE_BUCKET_UNSPECIFIED = 0;
323    // It's impossible to send requests without any headers in Cronet
324    REQUEST_HEADERS_SIZE_BUCKET_UNDER_ONE_KIB = 1;
325    REQUEST_HEADERS_SIZE_BUCKET_ONE_TO_TEN_KIB = 2;
326    REQUEST_HEADERS_SIZE_BUCKET_TEN_TO_TWENTY_FIVE_KIB = 3;
327    REQUEST_HEADERS_SIZE_BUCKET_TWENTY_FIVE_TO_FIFTY_KIB = 4;
328    REQUEST_HEADERS_SIZE_BUCKET_FIFTY_TO_HUNDRED_KIB = 5;
329    REQUEST_HEADERS_SIZE_BUCKET_OVER_HUNDRED_KIB = 6;
330  }
331
332  enum CronetRequestBodySizeBucket {
333    REQUEST_BODY_SIZE_BUCKET_UNSPECIFIED = 0;
334    REQUEST_BODY_SIZE_BUCKET_ZERO = 1;
335    REQUEST_BODY_SIZE_BUCKET_UNDER_TEN_KIB = 2;
336    REQUEST_BODY_SIZE_BUCKET_TEN_TO_FIFTY_KIB = 3;
337    REQUEST_BODY_SIZE_BUCKET_FIFTY_TO_TWO_HUNDRED_KIB = 4;
338    REQUEST_BODY_SIZE_BUCKET_TWO_HUNDRED_TO_FIVE_HUNDRED_KIB = 5;
339    REQUEST_BODY_SIZE_BUCKET_FIVE_HUNDRED_KIB_TO_ONE_MIB = 6;
340    REQUEST_BODY_SIZE_BUCKET_ONE_TO_FIVE_MIB = 7;
341    REQUEST_BODY_SIZE_BUCKET_OVER_FIVE_MIB = 8;
342  }
343
344  enum CronetResponseHeadersSizeBucket {
345    RESPONSE_HEADERS_SIZE_BUCKET_UNSPECIFIED = 0;
346    RESPONSE_HEADERS_SIZE_BUCKET_UNDER_ONE_KIB = 1;
347    RESPONSE_HEADERS_SIZE_BUCKET_ONE_TO_TEN_KIB = 2;
348    RESPONSE_HEADERS_SIZE_BUCKET_TEN_TO_TWENTY_FIVE_KIB = 3;
349    RESPONSE_HEADERS_SIZE_BUCKET_TWENTY_FIVE_TO_FIFTY_KIB = 4;
350    RESPONSE_HEADERS_SIZE_BUCKET_FIFTY_TO_HUNDRED_KIB = 5;
351    RESPONSE_HEADERS_SIZE_BUCKET_OVER_HUNDRED_KIB = 6;
352  }
353
354  enum CronetResponseBodySizeBucket {
355    RESPONSE_BODY_SIZE_BUCKET_UNSPECIFIED = 0;
356    RESPONSE_BODY_SIZE_BUCKET_ZERO = 1;
357    RESPONSE_BODY_SIZE_BUCKET_UNDER_TEN_KIB = 2;
358    RESPONSE_BODY_SIZE_BUCKET_TEN_TO_FIFTY_KIB = 3;
359    RESPONSE_BODY_SIZE_BUCKET_FIFTY_TO_TWO_HUNDRED_KIB = 4;
360    RESPONSE_BODY_SIZE_BUCKET_TWO_HUNDRED_TO_FIVE_HUNDRED_KIB = 5;
361    RESPONSE_BODY_SIZE_BUCKET_FIVE_HUNDRED_KIB_TO_ONE_MIB = 6;
362    RESPONSE_BODY_SIZE_BUCKET_ONE_TO_FIVE_MIB = 7;
363    RESPONSE_BODY_SIZE_BUCKET_OVER_FIVE_MIB = 8;
364  }
365}
366
367// Logged when the HTTP flags have been read.
368message CronetHttpFlagsInitialized {
369  // A weak-ID-like reference to the http flags loading operation.
370  // The field can be used to join with CronetEngineBuilderInitialized atom.
371  optional int64 cronet_http_flags_ref = 1;
372  // how long it took to load (or attempt to load) http flags.
373  // This field is set to -1 if flag loading was not attempted
374  // (e.g. because the app opted out of Cronet flag support).
375  // Note: There is no support for unset values, hence -1 is used.
376  optional int32 http_flags_latency_millis = 2 [default = -1];
377  // Determine whether flag loading was successful or not.
378  optional OptionalBoolean flags_successful = 3;
379
380  // The first 8 bytes of the MD5 hashes, interpreted as signed little-endian integers,
381  // of the HTTP flag names that the Cronet instance logging the atoms is
382  // actually running with.
383  repeated int64 http_flags_names = 4 [packed = true];
384
385  // The effective values of the flags, in the same order as
386  // http_flags_names.
387  // For boolean flags, this is 0 or 1.
388  // For integer flags, this is the value of the flag itself.
389  // For float values, this is the floating point value multiplied by 1 billion,
390  // rounded, and clamped to the int64 range. (This should result in distinct
391  // values for most commonly used floating point inputs.)
392  // For string or bytes flags, this is a hash of the value
393  // calculated in the same way as http_flags_names above.
394  repeated int64 http_flags_values = 5 [packed = true];
395}
396
397/*
398  ---------------------                                  -----------------
399  |                   |           createBuilder()        |               |  ================⦀
400  |     Provider      | -------------------------------> |     Builder   |                  ⦀
401  |                   |                                  |               |                  ⦀
402  |-------------------|    engine_builder_created_lat    |----------------                  ⦀
403                                                                 |                          ⦀
404                                                       Build()   | engine_created_latency   ⦀
405                                                                 |                          ⦀
406                                                                 V                          ⦀
407                          ------------------                 -------------------            ⦀
408                          |                |                 |                 |            ⦀
409                          |  REQ CAN START |  <------------- |      Engine     |            ⦀
410                          |WITHOUT BLOCKING|                 |                 |            ⦀
411                          |----------------|                 |-----------------|            ⦀
412                          ⦀                                                                 ⦀
413                          ==================================================================⦀
414               engine_async_latency (This takes a variable amount of time depending on async jobs)
415
416  engine_builder_created_latency: The wall time elapsed since createBuilder() has been called
417  until a builder has been returned.
418
419  engine_created_latency: The wall time elapsed since Build() has been called until a CronetEngine
420  has been returned.
421
422  engine_async_latency: The wall time elapsed since Build()
423  has been called until the returned CronetEngine
424  is usable (All Asynchronous setup calls have finished executing).
425*/
426
427// Logged once for each CronetSource when createBuilder() has returned.
428// This atom should normally be logged from Cronet API code (as opposed to impl code).
429// If the app is bundling a Cronet API version that is too old to know about this atom,
430// the impl takes responsibility for logging this atom and attempts to do so soon as
431// the impl is loaded. Some fields may be missing in this case.
432message CronetEngineBuilderInitialized {
433  // A weak-ID-like reference to the instance of the Cronet initialization.
434  // The field can be used to join subsequent engine creation and request
435  // metrics with the initialization details.
436  optional int64 cronet_initialization_ref = 1;
437
438  // How long it took to produce the first `CronetEngine.Builder` instance for the source specified.
439  // This field can be set by Api layer or Impl Layer, If this field was set by the Impl layer then
440  // the value of the field will be equal to -1.
441  optional int32 engine_builder_created_latency_millis = 2 [default = -1];
442
443  // Source of the Cronet being loaded
444  optional Source source = 3;
445
446  enum Source {
447    // Safe default, don't use explicitly.
448    CRONET_SOURCE_UNSPECIFIED = 0;
449    // Native-based Cronet implementation, bundled within the client app.
450    CRONET_SOURCE_EMBEDDED_NATIVE = 1;
451    // Java-based Cronet implementation, bundled within the client app.
452    CRONET_SOURCE_EMBEDDED_JAVA = 2;
453    // Native-based Cronet implementation, loaded from GMS Core (Google Play Services).
454    CRONET_SOURCE_GMSCORE_NATIVE = 3;
455    // Native-based Cronet implementation, loaded from the bootclasspath
456    // through the android.net.http.HttpEngine API.
457    CRONET_SOURCE_HTTPENGINE_NATIVE = 4;
458  }
459
460
461  // Whether the Provider successfully created a builder or not.
462  // This field can be set by Api layer or Impl Layer, If this field was set by the Impl layer then
463  // the value of the field will be equal to `UNSET`.
464  optional OptionalBoolean creation_successful = 4;
465
466  // A weak-ID-like reference to the http flags loading operation.
467  // The field can be used to join with CronetHttpFlagsInitialized atoms.
468  // Note: at the time of writing, loading of flags happens after the builder creation
469  // has returned. This means the corresponding CronetHttpFlagsLoaded is logged
470  // after or might not be logged at all (if there was a crash or
471  // the resulting builder was never used).
472  optional int64 cronet_http_flags_ref = 5;
473
474  // This field carries the value stored in the file below
475  // https://source.chromium.org/chromium/chromium/src/+/main:components/cronet/android/api/src/org/chromium/net/ApiVersion.template
476  optional int32 cronet_api_level = 6;
477
478  // This field carries the value stored in the file below
479  // https://source.chromium.org/chromium/chromium/src/+/main:components/cronet/android/java/src/org/chromium/net/impl/ImplVersion.template
480  optional int32 cronet_impl_api_level = 7;
481
482  // The following fields corresponds to the version of Chromium for which the implementation
483  // was compiled against as seen https://source.chromium.org/chromium/chromium/src/+/main:chrome/VERSION;l=1;bpv=0;bpt=0
484  optional int32 major_version = 8;
485  optional int32 minor_version = 9;
486  optional int32 build_version = 10;
487  optional int32 patch_version = 11;
488  // The Android UID of the process that Cronet was initialized in.
489  optional int32 uid = 12 [(is_uid) = true];
490}
491
492// Logged once for each CronetSource when the first CronetEngine is ready to be used.
493// Note that CronetInitialized may be logged after CronetEngineCreated because initialization
494// may continue in the background after the CronetEngine is instantiated.
495// One consequence is that cronet_initialization_ref can be broken if a
496// crash occurs after the engine is created but before initialization is complete.
497message CronetInitialized {
498  // A weak-ID-like reference to the instance of the Cronet initialization.
499  // The field can be used to join subsequent engine creation and request
500  // metrics with the native details.
501  optional int64 cronet_initialization_ref = 1;
502
503  // The wall clock time spent in the execution of the first call to `CronetEngine.Builder#build`
504  optional int32 engine_creation_latency_millis = 2 [default = -1];
505
506  // How much wall clock time was spent from the moment the first `CronetEngine.Builder#build()`
507  // was made and the point where Cronet is ready to send requests. Notably,
508  // this includes the time it took for any asynchronous background initialization code to complete
509  optional int32 engine_async_latency_millis = 3 [default = -1];
510}
511
512// Distinguishes between three states (unset / true / false)
513enum OptionalBoolean {
514  UNSET = 0;
515  TRUE = 1;
516  FALSE = 2;
517}