Add kAFF2 enabling the sending of AckFrequencyFrame upon handshake completion.

Protected by FLAGS_quic_reloadable_flag_quic_can_send_ack_frequency.

PiperOrigin-RevId: 337855733
Change-Id: I45e3c11605e37c01e217a7a86237f35cdfb806c9
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 57c9989..b5ed5c7 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -167,6 +167,8 @@
                                                  // AckFrequencyFrame.
 const QuicTag kAFF1 = TAG('A', 'F', 'F', '1');   // Use SRTT in building
                                                  // AckFrequencyFrame.
+const QuicTag kAFF2 = TAG('A', 'F', 'F', '2');   // Send AckFrequencyFrame upon
+                                                 // handshake completion.
 const QuicTag kSSLR = TAG('S', 'S', 'L', 'R');   // Slow Start Large Reduction.
 const QuicTag kNPRR = TAG('N', 'P', 'R', 'R');   // Pace at unity instead of PRR
 const QuicTag k2RTO = TAG('2', 'R', 'T', 'O');   // Close connection on 2 RTOs
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index c3fa8fb..e9fd55e 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -592,6 +592,10 @@
   }
 
   sent_packet_manager_.SetFromConfig(config);
+  if (perspective_ == Perspective::IS_SERVER &&
+      config.HasClientSentConnectionOption(kAFF2, perspective_)) {
+    send_ack_frequency_on_handshake_completion_ = true;
+  }
   if (config.HasReceivedBytesForConnectionId() &&
       can_truncate_connection_ids_) {
     packet_creator_.SetServerConnectionIdLength(
@@ -2636,6 +2640,7 @@
   if (!ack_frequency_sent_ && sent_packet_manager_.CanSendAckFrequency()) {
     if (packet_creator_.NextSendingPacketNumber() >=
         FirstSendingPacketNumber() + kMinReceivedBeforeAckDecimation) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 3, 3);
       ack_frequency_sent_ = true;
       auto frame = sent_packet_manager_.GetUpdatedAckFrequencyFrame();
       visitor_->SendAckFrequency(frame);
@@ -3402,6 +3407,20 @@
 
 void QuicConnection::OnHandshakeComplete() {
   sent_packet_manager_.SetHandshakeConfirmed();
+  if (send_ack_frequency_on_handshake_completion_ &&
+      sent_packet_manager_.CanSendAckFrequency()) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 2, 3);
+    auto ack_frequency_frame =
+        sent_packet_manager_.GetUpdatedAckFrequencyFrame();
+    // This AckFrequencyFrame is meant to only update the max_ack_delay. Set
+    // packet tolerance to the default value for now.
+    ack_frequency_frame.packet_tolerance =
+        kDefaultRetransmittablePacketsBeforeAck;
+    visitor_->SendAckFrequency(ack_frequency_frame);
+    if (!connected_) {
+      return;
+    }
+  }
   // This may have changed the retransmission timer, so re-arm it.
   SetRetransmissionAlarm();
   if (default_enable_5rto_blackhole_detection_) {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index a009954..2932584 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -1891,6 +1891,11 @@
   // Indicate whether any ENCRYPTION_HANDSHAKE packet has been sent.
   bool handshake_packet_sent_ = false;
 
+  // Indicate whether to send an AckFrequencyFrame upon handshake completion.
+  // The AckFrequencyFrame sent will updates client's max_ack_delay, which if
+  // chosen properly can reduce the CPU and bandwidth usage for ACK frames.
+  bool send_ack_frequency_on_handshake_completion_ = false;
+
   // Indicate whether AckFrequency frame has been sent.
   bool ack_frequency_sent_ = false;
 
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 738bc2e..42d19e2 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -12493,6 +12493,41 @@
   SendStreamDataToPeer(/*id=*/1, "baz", /*offset=*/6, NO_FIN, nullptr);
 }
 
+TEST_P(QuicConnectionTest, SendAckFrequencyFrameUponHandshakeCompletion) {
+  if (!version().HasIetfQuicFrames()) {
+    return;
+  }
+  SetQuicReloadableFlag(quic_can_send_ack_frequency, true);
+  set_perspective(Perspective::IS_SERVER);
+  EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _))
+      .Times(AnyNumber());
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
+
+  QuicConfig config;
+  QuicConfigPeer::SetReceivedMinAckDelayMs(&config, /*min_ack_delay_ms=*/1);
+  QuicTagVector quic_tag_vector;
+  // Enable sending AckFrequency upon handshake completion.
+  quic_tag_vector.push_back(kAFF2);
+  QuicConfigPeer::SetReceivedConnectionOptions(&config, quic_tag_vector);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  connection_.SetFromConfig(config);
+  QuicConnectionPeer::SetAddressValidated(&connection_);
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
+
+  QuicAckFrequencyFrame captured_frame;
+  EXPECT_CALL(visitor_, SendAckFrequency(_))
+      .WillOnce(Invoke([&captured_frame](const QuicAckFrequencyFrame& frame) {
+        captured_frame = frame;
+      }));
+
+  connection_.OnHandshakeComplete();
+
+  EXPECT_EQ(captured_frame.packet_tolerance, 2u);
+  EXPECT_EQ(captured_frame.max_ack_delay,
+            QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index a1126c0..01ec240 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -120,7 +120,7 @@
 
 // Default minimum delayed ack time, in ms (used only for sender control of ack
 // frequency).
-const uint32_t kDefaultMinAckDelayTimeMs = 1;
+const uint32_t kDefaultMinAckDelayTimeMs = 5;
 
 // Default shift of the ACK delay in the IETF QUIC ACK frame.
 const uint32_t kDefaultAckDelayExponent = 3;
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index bdad0e4..01e2840 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -726,13 +726,17 @@
     return frame;
   }
 
-  QUIC_RELOADABLE_FLAG_COUNT(quic_can_send_ack_frequency);
+  QUIC_RELOADABLE_FLAG_COUNT_N(quic_can_send_ack_frequency, 1, 3);
   frame.packet_tolerance = kMaxRetransmittablePacketsBeforeAck;
   auto rtt = use_smoothed_rtt_in_ack_delay_ ? rtt_stats_.SmoothedOrInitialRtt()
                                             : rtt_stats_.MinOrInitialRtt();
   frame.max_ack_delay = rtt * kAckDecimationDelay;
   frame.max_ack_delay = std::max(frame.max_ack_delay, peer_min_ack_delay_);
-
+  // TODO(haoyuewang) Remove this once kDefaultMinAckDelayTimeMs is updated to
+  // 5 ms on the client side.
+  frame.max_ack_delay =
+      std::max(frame.max_ack_delay,
+               QuicTime::Delta::FromMilliseconds(kDefaultMinAckDelayTimeMs));
   return frame;
 }
 
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 5504e8e..0ce3b43 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -4431,12 +4431,12 @@
 
   // Set up RTTs.
   auto* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
-  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(8),
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(80),
                        /*ack_delay=*/QuicTime::Delta::Zero(),
                        /*now=*/QuicTime::Zero());
   // Make sure srtt and min_rtt are different.
   rtt_stats->UpdateRtt(
-      QuicTime::Delta::FromMilliseconds(16),
+      QuicTime::Delta::FromMilliseconds(160),
       /*ack_delay=*/QuicTime::Delta::Zero(),
       /*now=*/QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(24));
 
@@ -4461,12 +4461,12 @@
 
   // Set up RTTs.
   auto* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
-  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(8),
+  rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(80),
                        /*ack_delay=*/QuicTime::Delta::Zero(),
                        /*now=*/QuicTime::Zero());
   // Make sure srtt and min_rtt are different.
   rtt_stats->UpdateRtt(
-      QuicTime::Delta::FromMilliseconds(16),
+      QuicTime::Delta::FromMilliseconds(160),
       /*ack_delay=*/QuicTime::Delta::Zero(),
       /*now=*/QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(24));