Replace legacy Google-specific parameter with individual parameters

Now that we've removed the majority of Google-specific parameters, we can now move the remaining 3 to their own transport parameter. This'll remove the dependency from QUIC+TLS on QUIC_CRYPTO handshake message code, and simplify debugging.

Tweak quic+tls transport parameters, protected by gfe2_restart_flag_quic_google_transport_param_send_new and gfe2_restart_flag_quic_google_transport_param_omit_old

PiperOrigin-RevId: 311438446
Change-Id: I95a61b9acf6523d845600fe70c2f752d5e30f28a
diff --git a/quic/core/crypto/transport_parameters.cc b/quic/core/crypto/transport_parameters.cc
index 4e761b3..3e286ad 100644
--- a/quic/core/crypto/transport_parameters.cc
+++ b/quic/core/crypto/transport_parameters.cc
@@ -49,6 +49,9 @@
 
   kMaxDatagramFrameSize = 0x20,
 
+  kInitialRoundTripTime = 0x3127,
+  kGoogleConnectionOptions = 0x3128,
+  kGoogleUserAgentId = 0x3129,
   kGoogleQuicParam = 18257,  // Used for non-standard Google-specific params.
   kGoogleQuicVersion =
       18258,  // Used to transmit version and supported_versions.
@@ -103,6 +106,12 @@
       return "active_connection_id_limit";
     case TransportParameters::kMaxDatagramFrameSize:
       return "max_datagram_frame_size";
+    case TransportParameters::kInitialRoundTripTime:
+      return "initial_round_trip_time";
+    case TransportParameters::kGoogleConnectionOptions:
+      return "google_connection_options";
+    case TransportParameters::kGoogleUserAgentId:
+      return "user_agent_id";
     case TransportParameters::kGoogleQuicParam:
       return "google";
     case TransportParameters::kGoogleQuicVersion:
@@ -130,6 +139,9 @@
     case TransportParameters::kPreferredAddress:
     case TransportParameters::kActiveConnectionIdLimit:
     case TransportParameters::kMaxDatagramFrameSize:
+    case TransportParameters::kInitialRoundTripTime:
+    case TransportParameters::kGoogleConnectionOptions:
+    case TransportParameters::kGoogleUserAgentId:
     case TransportParameters::kGoogleQuicParam:
     case TransportParameters::kGoogleQuicVersion:
       return true;
@@ -418,14 +430,31 @@
   }
   rv += active_connection_id_limit.ToString(/*for_use_in_list=*/true);
   rv += max_datagram_frame_size.ToString(/*for_use_in_list=*/true);
+  rv += initial_round_trip_time_us.ToString(/*for_use_in_list=*/true);
+  if (google_connection_options.has_value()) {
+    rv += " " + TransportParameterIdToString(kGoogleConnectionOptions) + " ";
+    bool first = true;
+    for (const QuicTag& connection_option : google_connection_options.value()) {
+      if (first) {
+        first = false;
+      } else {
+        rv += ",";
+      }
+      rv += QuicTagToString(connection_option);
+    }
+  }
+  if (user_agent_id.has_value()) {
+    rv += " " + TransportParameterIdToString(kGoogleUserAgentId) + " \"" +
+          user_agent_id.value() + "\"";
+  }
   if (google_quic_params) {
     rv += " " + TransportParameterIdToString(kGoogleQuicParam);
   }
-  rv += "]";
   for (const auto& kv : custom_parameters) {
     rv += " 0x" + quiche::QuicheTextUtils::Hex(static_cast<uint32_t>(kv.first));
     rv += "=" + quiche::QuicheTextUtils::HexEncode(kv.second);
   }
+  rv += "]";
   return rv;
 }
 
@@ -455,7 +484,8 @@
                                  kDefaultActiveConnectionIdLimitTransportParam,
                                  kMinActiveConnectionIdLimitTransportParam,
                                  kVarInt62MaxValue),
-      max_datagram_frame_size(kMaxDatagramFrameSize)
+      max_datagram_frame_size(kMaxDatagramFrameSize),
+      initial_round_trip_time_us(kInitialRoundTripTime)
 // Important note: any new transport parameters must be added
 // to TransportParameters::AreValid, SerializeTransportParameters and
 // ParseTransportParameters, TransportParameters's custom copy constructor, the
@@ -483,6 +513,9 @@
       disable_migration(other.disable_migration),
       active_connection_id_limit(other.active_connection_id_limit),
       max_datagram_frame_size(other.max_datagram_frame_size),
+      initial_round_trip_time_us(other.initial_round_trip_time_us),
+      google_connection_options(other.google_connection_options),
+      user_agent_id(other.user_agent_id),
       custom_parameters(other.custom_parameters) {
   if (other.preferred_address) {
     preferred_address = std::make_unique<TransportParameters::PreferredAddress>(
@@ -520,6 +553,10 @@
             rhs.active_connection_id_limit.value() &&
         max_datagram_frame_size.value() ==
             rhs.max_datagram_frame_size.value() &&
+        initial_round_trip_time_us.value() ==
+            rhs.initial_round_trip_time_us.value() &&
+        google_connection_options == rhs.google_connection_options &&
+        user_agent_id == rhs.user_agent_id &&
         custom_parameters == rhs.custom_parameters)) {
     return false;
   }
@@ -590,6 +627,15 @@
       return false;
     }
   }
+  if (perspective == Perspective::IS_SERVER &&
+      initial_round_trip_time_us.value() > 0) {
+    *error_details = "Server cannot send initial round trip time";
+    return false;
+  }
+  if (perspective == Perspective::IS_SERVER && user_agent_id.has_value()) {
+    *error_details = "Server cannot send user agent ID";
+    return false;
+  }
   const bool ok =
       idle_timeout_milliseconds.IsValid() && max_packet_size.IsValid() &&
       initial_max_data.IsValid() &&
@@ -598,7 +644,8 @@
       initial_max_stream_data_uni.IsValid() &&
       initial_max_streams_bidi.IsValid() && initial_max_streams_uni.IsValid() &&
       ack_delay_exponent.IsValid() && max_ack_delay.IsValid() &&
-      active_connection_id_limit.IsValid() && max_datagram_frame_size.IsValid();
+      active_connection_id_limit.IsValid() &&
+      max_datagram_frame_size.IsValid() && initial_round_trip_time_us.IsValid();
   if (!ok) {
     *error_details = "Invalid transport parameters " + this->ToString();
   }
@@ -691,7 +738,8 @@
       !in.ack_delay_exponent.Write(&writer, version) ||
       !in.max_ack_delay.Write(&writer, version) ||
       !in.active_connection_id_limit.Write(&writer, version) ||
-      !in.max_datagram_frame_size.Write(&writer, version)) {
+      !in.max_datagram_frame_size.Write(&writer, version) ||
+      !in.initial_round_trip_time_us.Write(&writer, version)) {
     QUIC_BUG << "Failed to write integers for " << in;
     return false;
   }
@@ -743,6 +791,42 @@
     }
   }
 
+  // Google-specific connection options.
+  if (in.google_connection_options.has_value()) {
+    static_assert(sizeof(in.google_connection_options.value().front()) == 4,
+                  "bad size");
+    uint64_t connection_options_length =
+        in.google_connection_options.value().size() * 4;
+    if (!WriteTransportParameterId(
+            &writer, TransportParameters::kGoogleConnectionOptions, version) ||
+        !WriteTransportParameterLength(&writer, connection_options_length,
+                                       version)) {
+      QUIC_BUG << "Failed to write google_connection_options of length "
+               << connection_options_length << " for " << in;
+      return false;
+    }
+    for (const QuicTag& connection_option :
+         in.google_connection_options.value()) {
+      if (!writer.WriteTag(connection_option)) {
+        QUIC_BUG << "Failed to write google_connection_option "
+                 << QuicTagToString(connection_option) << " for " << in;
+        return false;
+      }
+    }
+  }
+
+  // Google-specific user agent identifier.
+  if (in.user_agent_id.has_value()) {
+    if (!WriteTransportParameterId(
+            &writer, TransportParameters::kGoogleUserAgentId, version) ||
+        !WriteTransportParameterStringPiece(&writer, in.user_agent_id.value(),
+                                            version)) {
+      QUIC_BUG << "Failed to write Google user agent ID \""
+               << in.user_agent_id.value() << "\" for " << in;
+      return false;
+    }
+  }
+
   // Google-specific non-standard parameter.
   if (in.google_quic_params) {
     const QuicData& serialized_google_quic_params =
@@ -862,6 +946,7 @@
 
   QUIC_DLOG(INFO) << "Serialized " << in << " as " << writer.length()
                   << " bytes";
+
   return true;
 }
 
@@ -1033,6 +1118,32 @@
         parse_success =
             out->max_datagram_frame_size.Read(&value_reader, error_details);
         break;
+      case TransportParameters::kInitialRoundTripTime:
+        parse_success =
+            out->initial_round_trip_time_us.Read(&value_reader, error_details);
+        break;
+      case TransportParameters::kGoogleConnectionOptions: {
+        if (out->google_connection_options.has_value()) {
+          *error_details = "Received a second Google connection options";
+          return false;
+        }
+        out->google_connection_options = QuicTagVector{};
+        while (!value_reader.IsDoneReading()) {
+          QuicTag connection_option;
+          if (!value_reader.ReadTag(&connection_option)) {
+            *error_details = "Failed to read a Google connection option";
+            return false;
+          }
+          out->google_connection_options.value().push_back(connection_option);
+        }
+      } break;
+      case TransportParameters::kGoogleUserAgentId:
+        if (out->user_agent_id.has_value()) {
+          *error_details = "Received a second user agent ID";
+          return false;
+        }
+        out->user_agent_id = std::string(value_reader.ReadRemainingPayload());
+        break;
       case TransportParameters::kGoogleQuicParam: {
         if (out->google_quic_params) {
           *error_details = "Received a second Google parameter";
diff --git a/quic/core/crypto/transport_parameters.h b/quic/core/crypto/transport_parameters.h
index 9f9e616..9dec484 100644
--- a/quic/core/crypto/transport_parameters.h
+++ b/quic/core/crypto/transport_parameters.h
@@ -184,6 +184,16 @@
   // the sender accepts. See draft-ietf-quic-datagram.
   IntegerParameter max_datagram_frame_size;
 
+  // Google-specific transport parameter that carries an estimate of the
+  // initial round-trip time in microseconds.
+  IntegerParameter initial_round_trip_time_us;
+
+  // Google-specific connection options.
+  quiche::QuicheOptional<QuicTagVector> google_connection_options;
+
+  // Google-specific user agent identifier.
+  quiche::QuicheOptional<std::string> user_agent_id;
+
   // Transport parameters used by Google QUIC but not IETF QUIC. This is
   // serialized into a TransportParameter struct with a TransportParameterId of
   // kGoogleQuicParamId.
diff --git a/quic/core/crypto/transport_parameters_test.cc b/quic/core/crypto/transport_parameters_test.cc
index c3d5d57..1fc1f5c 100644
--- a/quic/core/crypto/transport_parameters_test.cc
+++ b/quic/core/crypto/transport_parameters_test.cc
@@ -7,7 +7,9 @@
 #include <cstring>
 #include <utility>
 
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
+#include "net/third_party/quiche/src/quic/core/quic_tag.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
@@ -38,6 +40,7 @@
 const uint64_t kFakeMaxAckDelay = 51;
 const bool kFakeDisableMigration = true;
 const uint64_t kFakeActiveConnectionIdLimit = 52;
+const uint64_t kFakeInitialRoundTripTime = 53;
 const uint8_t kFakePreferredStatelessResetTokenData[16] = {
     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
     0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F};
@@ -100,6 +103,15 @@
       preferred_address);
 }
 
+QuicTagVector CreateFakeGoogleConnectionOptions() {
+  return {kALPN, MakeQuicTag('E', 'F', 'G', 0x00),
+          MakeQuicTag('H', 'I', 'J', 0xff)};
+}
+
+std::string CreateFakeUserAgentId() {
+  return "FakeUAID";
+}
+
 void RemoveGreaseParameters(TransportParameters* params) {
   std::vector<TransportParameters::TransportParameterId> grease_params;
   for (const auto& kv : params->custom_parameters) {
@@ -237,6 +249,9 @@
   orig_params.preferred_address = CreateFakePreferredAddress();
   orig_params.active_connection_id_limit.set_value(
       kFakeActiveConnectionIdLimit);
+  orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+  orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
+  orig_params.user_agent_id = CreateFakeUserAgentId();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
 
@@ -264,6 +279,9 @@
   orig_params.disable_migration = kFakeDisableMigration;
   orig_params.active_connection_id_limit.set_value(
       kFakeActiveConnectionIdLimit);
+  orig_params.initial_round_trip_time_us.set_value(kFakeInitialRoundTripTime);
+  orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
+  orig_params.user_agent_id = CreateFakeUserAgentId();
   orig_params.custom_parameters[kCustomParameter1] = kCustomParameter1Value;
   orig_params.custom_parameters[kCustomParameter2] = kCustomParameter2Value;
 
@@ -306,6 +324,7 @@
   orig_params.preferred_address = CreateFakePreferredAddress();
   orig_params.active_connection_id_limit.set_value(
       kFakeActiveConnectionIdLimit);
+  orig_params.google_connection_options = CreateFakeGoogleConnectionOptions();
 
   std::vector<uint8_t> serialized;
   ASSERT_TRUE(SerializeTransportParameters(version_, orig_params, &serialized));
@@ -433,7 +452,7 @@
 TEST_P(TransportParametersTest, ParseClientParams) {
   // clang-format off
   const uint8_t kClientParamsOld[] = {
-      0x00, 0x49,              // length of the parameters array that follows
+      0x00, 0x6a,              // length of the parameters array that follows
       // idle_timeout
       0x00, 0x01,  // parameter id
       0x00, 0x02,  // length
@@ -481,6 +500,20 @@
       0x00, 0x0e,  // parameter id
       0x00, 0x01,  // length
       0x34,  // value
+      // initial_round_trip_time_us
+      0x31, 0x27,  // parameter id
+      0x00, 0x01,  // length
+      0x35,  // value
+      // google_connection_options
+      0x31, 0x28,  // parameter id
+      0x00, 0x0c,  // length
+      'A', 'L', 'P', 'N',  // value
+      'E', 'F', 'G', 0x00,
+      'H', 'I', 'J', 0xff,
+      // user_agent_id
+      0x31, 0x29,  // parameter id
+      0x00, 0x08,  // length
+      'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D',  // value
       // Google version extension
       0x47, 0x52,  // parameter id
       0x00, 0x04,  // length
@@ -534,6 +567,20 @@
       0x0e,  // parameter id
       0x01,  // length
       0x34,  // value
+      // initial_round_trip_time_us
+      0x71, 0x27,  // parameter id
+      0x01,  // length
+      0x35,  // value
+      // google_connection_options
+      0x71, 0x28,  // parameter id
+      0x0c,  // length
+      'A', 'L', 'P', 'N',  // value
+      'E', 'F', 'G', 0x00,
+      'H', 'I', 'J', 0xff,
+      // user_agent_id
+      0x71, 0x29,  // parameter id
+      0x08,  // length
+      'F', 'a', 'k', 'e', 'U', 'A', 'I', 'D',  // value
       // Google version extension
       0x80, 0x00, 0x47, 0x52,  // parameter id
       0x04,  // length
@@ -578,6 +625,13 @@
   EXPECT_EQ(kFakeDisableMigration, new_params.disable_migration);
   EXPECT_EQ(kFakeActiveConnectionIdLimit,
             new_params.active_connection_id_limit.value());
+  EXPECT_EQ(kFakeInitialRoundTripTime,
+            new_params.initial_round_trip_time_us.value());
+  ASSERT_TRUE(new_params.google_connection_options.has_value());
+  EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
+            new_params.google_connection_options.value());
+  ASSERT_TRUE(new_params.user_agent_id.has_value());
+  EXPECT_EQ(CreateFakeUserAgentId(), new_params.user_agent_id.value());
 }
 
 TEST_P(TransportParametersTest,
@@ -745,7 +799,7 @@
 TEST_P(TransportParametersTest, ParseServerParams) {
   // clang-format off
   const uint8_t kServerParamsOld[] = {
-      0x00, 0xa7,  // length of parameters array that follows
+      0x00, 0xb7,  // length of parameters array that follows
       // original_connection_id
       0x00, 0x00,  // parameter id
       0x00, 0x08,  // length
@@ -814,6 +868,12 @@
       0x00, 0x0e,  // parameter id
       0x00, 0x01,  // length
       0x34,  // value
+      // google_connection_options
+      0x31, 0x28,  // parameter id
+      0x00, 0x0c,  // length
+      'A', 'L', 'P', 'N',  // value
+      'E', 'F', 'G', 0x00,
+      'H', 'I', 'J', 0xff,
       // Google version extension
       0x47, 0x52,  // parameter id
       0x00, 0x0d,  // length
@@ -891,6 +951,12 @@
       0x0e,  // parameter id
       0x01,  // length
       0x34,  // value
+      // google_connection_options
+      0x71, 0x28,  // parameter id
+      0x0c,  // length
+      'A', 'L', 'P', 'N',  // value
+      'E', 'F', 'G', 0x00,
+      'H', 'I', 'J', 0xff,
       // Google version extension
       0x80, 0x00, 0x47, 0x52,  // parameter id
       0x0d,  // length
@@ -951,6 +1017,10 @@
             new_params.preferred_address->stateless_reset_token);
   EXPECT_EQ(kFakeActiveConnectionIdLimit,
             new_params.active_connection_id_limit.value());
+  ASSERT_TRUE(new_params.google_connection_options.has_value());
+  EXPECT_EQ(CreateFakeGoogleConnectionOptions(),
+            new_params.google_connection_options.value());
+  EXPECT_FALSE(new_params.user_agent_id.has_value());
 }
 
 TEST_P(TransportParametersTest, ParseServerParametersRepeated) {
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
index 865aef8..7c781f4 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -686,7 +686,7 @@
   return bytes_for_connection_id_.GetReceivedValue();
 }
 
-void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32_t rtt) {
+void QuicConfig::SetInitialRoundTripTimeUsToSend(uint64_t rtt) {
   initial_round_trip_time_us_.SetSendValue(rtt);
 }
 
@@ -694,7 +694,7 @@
   return initial_round_trip_time_us_.HasReceivedValue();
 }
 
-uint32_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
+uint64_t QuicConfig::ReceivedInitialRoundTripTimeUs() const {
   return initial_round_trip_time_us_.GetReceivedValue();
 }
 
@@ -702,7 +702,7 @@
   return initial_round_trip_time_us_.HasSendValue();
 }
 
-uint32_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
+uint64_t QuicConfig::GetInitialRoundTripTimeUsToSend() const {
   return initial_round_trip_time_us_.GetSendValue();
 }
 
@@ -1138,12 +1138,29 @@
         active_connection_id_limit_.GetSendValue());
   }
 
-  if (!params->google_quic_params) {
-    params->google_quic_params = std::make_unique<CryptoHandshakeMessage>();
+  if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
+    QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 1, 3);
+    if (initial_round_trip_time_us_.HasSendValue()) {
+      params->initial_round_trip_time_us.set_value(
+          initial_round_trip_time_us_.GetSendValue());
+    }
+    if (connection_options_.HasSendValues() &&
+        !connection_options_.GetSendValues().empty()) {
+      params->google_connection_options = connection_options_.GetSendValues();
+    }
   }
-  initial_round_trip_time_us_.ToHandshakeMessage(
-      params->google_quic_params.get());
-  connection_options_.ToHandshakeMessage(params->google_quic_params.get());
+
+  if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) {
+    if (!params->google_quic_params) {
+      params->google_quic_params = std::make_unique<CryptoHandshakeMessage>();
+    }
+    initial_round_trip_time_us_.ToHandshakeMessage(
+        params->google_quic_params.get());
+    connection_options_.ToHandshakeMessage(params->google_quic_params.get());
+  } else {
+    QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_omit_old, 1, 3);
+  }
+
   params->custom_parameters = custom_transport_parameters_to_send_;
 
   return true;
@@ -1242,22 +1259,41 @@
   active_connection_id_limit_.SetReceivedValue(
       params.active_connection_id_limit.value());
 
-  const CryptoHandshakeMessage* peer_params = params.google_quic_params.get();
-  if (peer_params != nullptr) {
-    QuicErrorCode error = initial_round_trip_time_us_.ProcessPeerHello(
-        *peer_params, hello_type, error_details);
-    if (error != QUIC_NO_ERROR) {
-      DCHECK(!error_details->empty());
-      return error;
+  bool google_params_already_parsed = false;
+  if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
+    QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_send_new, 2, 3);
+    if (params.initial_round_trip_time_us.value() > 0) {
+      google_params_already_parsed = true;
+      initial_round_trip_time_us_.SetReceivedValue(
+          params.initial_round_trip_time_us.value());
     }
-    error = connection_options_.ProcessPeerHello(*peer_params, hello_type,
-                                                 error_details);
-    if (error != QUIC_NO_ERROR) {
-      DCHECK(!error_details->empty());
-      return error;
+    if (params.google_connection_options.has_value()) {
+      google_params_already_parsed = true;
+      connection_options_.SetReceivedValues(
+          params.google_connection_options.value());
     }
   }
 
+  if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) {
+    const CryptoHandshakeMessage* peer_params = params.google_quic_params.get();
+    if (peer_params != nullptr && !google_params_already_parsed) {
+      QuicErrorCode error = initial_round_trip_time_us_.ProcessPeerHello(
+          *peer_params, hello_type, error_details);
+      if (error != QUIC_NO_ERROR) {
+        DCHECK(!error_details->empty());
+        return error;
+      }
+      error = connection_options_.ProcessPeerHello(*peer_params, hello_type,
+                                                   error_details);
+      if (error != QUIC_NO_ERROR) {
+        DCHECK(!error_details->empty());
+        return error;
+      }
+    }
+  } else {
+    QUIC_RESTART_FLAG_COUNT_N(quic_google_transport_param_omit_old, 2, 3);
+  }
+
   received_custom_transport_parameters_ = params.custom_parameters;
 
   if (!is_resumption) {
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h
index 893e3e7..4d2bacc 100644
--- a/quic/core/quic_config.h
+++ b/quic/core/quic_config.h
@@ -331,11 +331,11 @@
   uint32_t ReceivedBytesForConnectionId() const;
 
   // Estimated initial round trip time in us.
-  void SetInitialRoundTripTimeUsToSend(uint32_t rtt_us);
+  void SetInitialRoundTripTimeUsToSend(uint64_t rtt_us);
   bool HasReceivedInitialRoundTripTimeUs() const;
-  uint32_t ReceivedInitialRoundTripTimeUs() const;
+  uint64_t ReceivedInitialRoundTripTimeUs() const;
   bool HasInitialRoundTripTimeUsToSend() const;
-  uint32_t GetInitialRoundTripTimeUsToSend() const;
+  uint64_t GetInitialRoundTripTimeUsToSend() const;
 
   // Sets an initial stream flow control window size to transmit to the peer.
   void SetInitialStreamFlowControlWindowToSend(uint64_t window_bytes);
@@ -528,7 +528,7 @@
   // the legacy header format used only by Q043 at this point.
   QuicFixedUint32 bytes_for_connection_id_;
   // Initial round trip time estimate in microseconds.
-  QuicFixedUint32 initial_round_trip_time_us_;
+  QuicFixedUint62 initial_round_trip_time_us_;
 
   // Initial IETF QUIC stream flow control receive windows in bytes.
   // Incoming bidirectional streams.
diff --git a/quic/core/tls_client_handshaker.cc b/quic/core/tls_client_handshaker.cc
index 0378ed0..30a9ac4 100644
--- a/quic/core/tls_client_handshaker.cc
+++ b/quic/core/tls_client_handshaker.cc
@@ -207,7 +207,14 @@
   if (!session()->config()->FillTransportParameters(&params)) {
     return false;
   }
-  params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
+  if (GetQuicRestartFlag(quic_google_transport_param_send_new)) {
+    if (!user_agent_id_.empty()) {
+      params.user_agent_id = user_agent_id_;
+    }
+  }
+  if (!GetQuicRestartFlag(quic_google_transport_param_omit_old)) {
+    params.google_quic_params->SetStringPiece(kUAID, user_agent_id_);
+  }
 
   std::vector<uint8_t> param_bytes;
   return SerializeTransportParameters(session()->connection()->version(),