Add a kAFFE client option to enable the usage of AckFrequencyFrame, including
(1) Send min_ack_delay from client.
(2) Update client upon receiving AckFrequencyFrame.

Separate options will enable actual sending of AckFrequencyFrame and is in follow-up CLs.

PiperOrigin-RevId: 332049097
Change-Id: Ibc267ab580ce7ed5638fd2ad62226f67c1604a85
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 80273f0..07f2bae 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -159,6 +159,7 @@
                                                  // received before acking
 const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q');   // Send an immediate ack after
                                                  // 1 RTT of not receiving.
+const QuicTag kAFFE = TAG('A', 'F', 'F', 'E');   // AckFrequencyFrame Enabled.
 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/frames/quic_ack_frequency_frame.cc b/quic/core/frames/quic_ack_frequency_frame.cc
index b8c7efa..1486327 100644
--- a/quic/core/frames/quic_ack_frequency_frame.cc
+++ b/quic/core/frames/quic_ack_frequency_frame.cc
@@ -8,6 +8,16 @@
 
 namespace quic {
 
+QuicAckFrequencyFrame::QuicAckFrequencyFrame(
+    QuicControlFrameId control_frame_id,
+    uint64_t sequence_number,
+    uint64_t packet_tolerance,
+    QuicTime::Delta max_ack_delay)
+    : control_frame_id(control_frame_id),
+      sequence_number(sequence_number),
+      packet_tolerance(packet_tolerance),
+      max_ack_delay(max_ack_delay) {}
+
 std::ostream& operator<<(std::ostream& os, const QuicAckFrequencyFrame& frame) {
   os << "{ control_frame_id: " << frame.control_frame_id
      << ", sequence_number: " << frame.sequence_number
diff --git a/quic/core/frames/quic_ack_frequency_frame.h b/quic/core/frames/quic_ack_frequency_frame.h
index 52b70da..3f9397c 100644
--- a/quic/core/frames/quic_ack_frequency_frame.h
+++ b/quic/core/frames/quic_ack_frequency_frame.h
@@ -21,8 +21,14 @@
       std::ostream& os,
       const QuicAckFrequencyFrame& ack_frequency_frame);
 
-  // A unique identifier of this control frame. 0 when this frame is received,
-  // and non-zero when sent.
+  QuicAckFrequencyFrame() = default;
+  QuicAckFrequencyFrame(QuicControlFrameId control_frame_id,
+                        uint64_t sequence_number,
+                        uint64_t packet_tolerance,
+                        QuicTime::Delta max_ack_delay);
+
+  // A unique identifier of this control frame. 0 when this frame is
+  // received, and non-zero when sent.
   QuicControlFrameId control_frame_id = kInvalidControlFrameId;
 
   // If true, do not ack immediately upon observeation of packet reordering.
@@ -34,10 +40,11 @@
 
   // The maximum number of ack-eliciting packets after which the receiver sends
   // an acknowledgement. Invald if == 0.
-  uint64_t packet_tolerance = 0;
+  uint64_t packet_tolerance = 2;
 
   // The maximum time that ack packets can be delayed.
-  QuicTime::Delta max_ack_delay = QuicTime::Delta::Zero();
+  QuicTime::Delta max_ack_delay =
+      QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc
index 23597e2..89a76af 100644
--- a/quic/core/quic_config.cc
+++ b/quic/core/quic_config.cc
@@ -1326,6 +1326,7 @@
           *error_details = "MinAckDelay is greater than MaxAckDelay.";
           return IETF_QUIC_PROTOCOL_VIOLATION;
         }
+        QUIC_RELOADABLE_FLAG_COUNT(quic_record_received_min_ack_delay);
         min_ack_delay_ms_.SetReceivedValue(params.min_ack_delay_us.value() /
                                            kNumMicrosPerMilli);
       }
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index fc72c59..bae994f 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -1708,13 +1708,24 @@
   return connected_;
 }
 
-bool QuicConnection::OnAckFrequencyFrame(
-    const QuicAckFrequencyFrame& /*frame*/) {
+bool QuicConnection::OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) {
   UpdatePacketContent(ACK_FREQUENCY_FRAME);
-  // TODO(b/148614353): implement this fully.
-  QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame.";
-  return false;
+  if (!can_receive_ack_frequency_frame_) {
+    QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame.";
+    return false;
+  }
+  if (auto packet_number_space =
+          QuicUtils::GetPacketNumberSpace(last_decrypted_packet_level_) ==
+          APPLICATION_DATA) {
+    uber_received_packet_manager_.OnAckFrequencyFrame(frame);
+  } else {
+    QUIC_LOG_EVERY_N_SEC(ERROR, 120)
+        << "Get AckFrequencyFrame in packet number space "
+        << packet_number_space;
+  }
+  return true;
 }
+
 bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) {
   DCHECK(connected_);
 
@@ -4800,11 +4811,6 @@
       new_value);
 }
 
-void QuicConnection::set_ack_frequency(size_t new_value) {
-  DCHECK_GT(new_value, 0u);
-  uber_received_packet_manager_.set_ack_frequency(new_value);
-}
-
 const QuicAckFrame& QuicConnection::ack_frame() const {
   if (SupportsMultiplePacketNumberSpaces()) {
     return uber_received_packet_manager_.GetAckFrame(
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index dcd655b..5461908 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -925,8 +925,6 @@
   size_t min_received_before_ack_decimation() const;
   void set_min_received_before_ack_decimation(size_t new_value);
 
-  void set_ack_frequency(size_t new_value);
-
   // If |defer| is true, configures the connection to defer sending packets in
   // response to an ACK to the SendAlarm. If |defer| is false, packets may be
   // sent immediately after receiving an ACK.
@@ -1030,6 +1028,14 @@
   // false.
   bool MaybeTestLiveness();
 
+  bool can_receive_ack_frequency_frame() const {
+    return can_receive_ack_frequency_frame_;
+  }
+
+  void set_can_receive_ack_frequency_frame() {
+    can_receive_ack_frequency_frame_ = true;
+  }
+
  protected:
   // Calls cancel() on all the alarms owned by this connection.
   void CancelAllAlarms();
@@ -1770,6 +1776,8 @@
   // --gfe2_reloadable_flag_quic_start_peer_migration_earlier.
   bool send_path_response_ = start_peer_migration_earlier_ &&
                              GetQuicReloadableFlag(quic_send_path_response);
+  // True if AckFrequencyFrame is supported.
+  bool can_receive_ack_frequency_frame_ = false;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index fdc4d7a..940a988 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2976,12 +2976,20 @@
   ProcessAckPacket(&frame2);
 }
 
-TEST_P(QuicConnectionTest, AckSentEveryNthPacket) {
-  connection_.set_ack_frequency(3);
+TEST_P(QuicConnectionTest, AckFrequencyUpdatedFromAckFrequencyFrame) {
+  if (!GetParam().version.HasIetfQuicFrames()) {
+    return;
+  }
+
+  QuicAckFrequencyFrame frame;
+  frame.packet_tolerance = 3;
+
+  connection_.set_can_receive_ack_frequency_frame();
+  connection_.OnDecryptedPacket(ENCRYPTION_FORWARD_SECURE);
+  connection_.OnAckFrequencyFrame(frame);
 
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(39);
-
   // Expect 13 acks, every 3rd packet.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(13);
   // Receives packets 1 - 39.
@@ -2990,6 +2998,29 @@
   }
 }
 
+TEST_P(QuicConnectionTest,
+       AckFrequencyFrameOutsideApplicationDataNumberSpaceIsIgnored) {
+  if (!GetParam().version.HasIetfQuicFrames()) {
+    return;
+  }
+
+  QuicAckFrequencyFrame frame;
+  frame.packet_tolerance = 3;
+  connection_.set_can_receive_ack_frequency_frame();
+  connection_.OnDecryptedPacket(ENCRYPTION_HANDSHAKE);
+  connection_.OnAckFrequencyFrame(frame);
+  connection_.OnDecryptedPacket(ENCRYPTION_FORWARD_SECURE);
+
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(60);
+  // Expect 30 acks, every 2nd (instead of 3rd) packet.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(30);
+  // Receives packets 1 - 60.
+  for (size_t i = 1; i <= 60; ++i) {
+    ProcessDataPacket(i);
+  }
+}
+
 TEST_P(QuicConnectionTest, AckDecimationReducesAcks) {
   const size_t kMinRttMs = 40;
   RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats());
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index 1c9218a..9a84d97 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -47,11 +47,13 @@
       ack_decimation_delay_(kAckDecimationDelay),
       unlimited_ack_decimation_(false),
       one_immediate_ack_(false),
+      ignore_order_(false),
       local_max_ack_delay_(
           QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
       ack_timeout_(QuicTime::Zero()),
       time_of_previous_received_packet_(QuicTime::Zero()),
-      was_last_packet_missing_(false) {}
+      was_last_packet_missing_(false),
+      last_ack_frequency_frame_sequence_number_(-1) {}
 
 QuicReceivedPacketManager::~QuicReceivedPacketManager() {}
 
@@ -194,8 +196,9 @@
 QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay(
     QuicPacketNumber last_received_packet_number,
     const RttStats& rtt_stats) const {
-  if (last_received_packet_number <
-      PeerFirstSendingPacketNumber() + min_received_before_ack_decimation_) {
+  if (AckFrequencyFrameReceived() ||
+      last_received_packet_number < PeerFirstSendingPacketNumber() +
+                                        min_received_before_ack_decimation_) {
     return local_max_ack_delay_;
   }
 
@@ -212,6 +215,11 @@
 
 void QuicReceivedPacketManager::MaybeUpdateAckFrequency(
     QuicPacketNumber last_received_packet_number) {
+  if (AckFrequencyFrameReceived()) {
+    // Skip Ack Decimation below after receiving an AckFrequencyFrame from the
+    // other end point.
+    return;
+  }
   if (last_received_packet_number <
       PeerFirstSendingPacketNumber() + min_received_before_ack_decimation_) {
     return;
@@ -231,7 +239,8 @@
     return;
   }
 
-  if (was_last_packet_missing_ && last_sent_largest_acked_.IsInitialized() &&
+  if (!ignore_order_ && was_last_packet_missing_ &&
+      last_sent_largest_acked_.IsInitialized() &&
       last_received_packet_number < last_sent_largest_acked_) {
     // Only ack immediately if an ACK frame was sent with a larger largest acked
     // than the newly received packet number.
@@ -252,7 +261,7 @@
     return;
   }
 
-  if (HasNewMissingPackets()) {
+  if (!ignore_order_ && HasNewMissingPackets()) {
     ack_timeout_ = now;
     return;
   }
@@ -314,4 +323,17 @@
   return ack_frame_.packets.Empty();
 }
 
+void QuicReceivedPacketManager::OnAckFrequencyFrame(
+    const QuicAckFrequencyFrame& frame) {
+  int64_t new_sequence_number = frame.sequence_number;
+  if (new_sequence_number <= last_ack_frequency_frame_sequence_number_) {
+    // Ignore old ACK_FREQUENCY frames.
+    return;
+  }
+  last_ack_frequency_frame_sequence_number_ = new_sequence_number;
+  ack_frequency_ = frame.packet_tolerance;
+  local_max_ack_delay_ = frame.max_ack_delay;
+  ignore_order_ = frame.ignore_order;
+}
+
 }  // namespace quic
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h
index c8b55c4..78ed411 100644
--- a/quic/core/quic_received_packet_manager.h
+++ b/quic/core/quic_received_packet_manager.h
@@ -5,6 +5,8 @@
 #ifndef QUICHE_QUIC_CORE_QUIC_RECEIVED_PACKET_MANAGER_H_
 #define QUICHE_QUIC_CORE_QUIC_RECEIVED_PACKET_MANAGER_H_
 
+#include <cstddef>
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
 #include "net/third_party/quiche/src/quic/core/quic_config.h"
 #include "net/third_party/quiche/src/quic/core/quic_framer.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
@@ -123,6 +125,8 @@
 
   QuicTime ack_timeout() const { return ack_timeout_; }
 
+  void OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame);
+
  private:
   friend class test::QuicConnectionPeer;
   friend class test::QuicReceivedPacketManagerPeer;
@@ -137,6 +141,10 @@
   QuicTime::Delta GetMaxAckDelay(QuicPacketNumber last_received_packet_number,
                                  const RttStats& rtt_stats) const;
 
+  bool AckFrequencyFrameReceived() const {
+    return last_ack_frequency_frame_sequence_number_ >= 0;
+  }
+
   // Least packet number of the the packet sent by the peer for which it
   // hasn't received an ack.
   QuicPacketNumber peer_least_packet_awaiting_ack_;
@@ -177,6 +185,8 @@
   bool unlimited_ack_decimation_;
   // When true, only send 1 immediate ACK when reordering is detected.
   bool one_immediate_ack_;
+  // When true, do not ack immediately upon observation of packet reordering.
+  bool ignore_order_;
 
   // The local node's maximum ack delay time. This is the maximum amount of
   // time to wait before sending an acknowledgement.
@@ -192,6 +202,10 @@
 
   // Last sent largest acked, which gets updated when ACK was successfully sent.
   QuicPacketNumber last_sent_largest_acked_;
+
+  // The sequence number of the last received AckFrequencyFrame. Negative if
+  // none received.
+  int64_t last_ack_frequency_frame_sequence_number_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_received_packet_manager_test.cc b/quic/core/quic_received_packet_manager_test.cc
index 2cf8227..c8d1638 100644
--- a/quic/core/quic_received_packet_manager_test.cc
+++ b/quic/core/quic_received_packet_manager_test.cc
@@ -5,6 +5,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
 
 #include <algorithm>
+#include <cstddef>
 #include <ostream>
 #include <vector>
 
@@ -532,6 +533,125 @@
   CheckAckTimeout(clock_.ApproximateNow());
 }
 
+TEST_F(QuicReceivedPacketManagerTest,
+       UpdateMaxAckDelayAndAckFrequencyFromAckFrequencyFrame) {
+  EXPECT_FALSE(HasPendingAck());
+
+  QuicAckFrequencyFrame frame;
+  frame.max_ack_delay = QuicTime::Delta::FromMilliseconds(10);
+  frame.packet_tolerance = 5;
+  received_manager_.OnAckFrequencyFrame(frame);
+
+  for (int i = 1; i <= 50; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % frame.packet_tolerance == 0) {
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + frame.max_ack_delay);
+    }
+  }
+}
+
+TEST_F(QuicReceivedPacketManagerTest,
+       DisableOutOfOrderAckByIgnoreOrderFromAckFrequencyFrame) {
+  EXPECT_FALSE(HasPendingAck());
+
+  QuicAckFrequencyFrame frame;
+  frame.max_ack_delay = kDelayedAckTime;
+  frame.packet_tolerance = 2;
+  frame.ignore_order = true;
+  received_manager_.OnAckFrequencyFrame(frame);
+
+  RecordPacketReceipt(4, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 4);
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+  RecordPacketReceipt(5, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 5);
+  // Immediate ack is sent as this is the 2nd packet of every two packets.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(3, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 3);
+  // Don't ack as ignore_order is set by AckFrequencyFrame.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 2);
+  // Immediate ack is sent as this is the 2nd packet of every two packets.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 1);
+  // Don't ack as ignore_order is set by AckFrequencyFrame.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+}
+
+TEST_F(QuicReceivedPacketManagerTest,
+       DisableMissingPaketsAckByIgnoreOrderFromAckFrequencyFrame) {
+  EXPECT_FALSE(HasPendingAck());
+  QuicConfig config;
+  config.SetConnectionOptionsToSend({kAFFE});
+  received_manager_.SetFromConfig(config, Perspective::IS_CLIENT);
+
+  QuicAckFrequencyFrame frame;
+  frame.max_ack_delay = kDelayedAckTime;
+  frame.packet_tolerance = 2;
+  frame.ignore_order = true;
+  received_manager_.OnAckFrequencyFrame(frame);
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 1);
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 2);
+  // Immediate ack is sent as this is the 2nd packet of every two packets.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(4, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 4);
+  // Don't ack even if packet 3 is newly missing as ignore_order is set by
+  // AckFrequencyFrame.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+
+  RecordPacketReceipt(5, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 5);
+  // Immediate ack is sent as this is the 2nd packet of every two packets.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(7, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 7);
+  // Don't ack even if packet 6 is newly missing as ignore_order is set by
+  // AckFrequencyFrame.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+}
+
+TEST_F(QuicReceivedPacketManagerTest,
+       AckDecimationDisabledWhenAckFrequencyFrameIsReceived) {
+  EXPECT_FALSE(HasPendingAck());
+
+  QuicAckFrequencyFrame frame;
+  frame.max_ack_delay = kDelayedAckTime;
+  frame.packet_tolerance = 3;
+  frame.ignore_order = true;
+  received_manager_.OnAckFrequencyFrame(frame);
+
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  uint64_t FiftyPacketsAfterAckDecimation = kFirstDecimatedPacket + 50;
+  for (uint64_t i = 1; i < FiftyPacketsAfterAckDecimation; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 3 == 0) {
+      // Ack every 3 packets as decimation is disabled.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      // Ack at default delay as decimation is disabled.
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index da9a925..e3c389b 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -122,6 +122,12 @@
   connection_->SetSessionNotifier(this);
   connection_->SetDataProducer(this);
   connection_->SetFromConfig(config_);
+  if (perspective_ == Perspective::IS_CLIENT &&
+      config_.HasClientRequestedIndependentOption(kAFFE, perspective_) &&
+      version().HasIetfQuicFrames()) {
+    connection_->set_can_receive_ack_frequency_frame();
+    config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs);
+  }
   if (perspective() == Perspective::IS_CLIENT && version().UsesTls() &&
       !version().HasHandshakeDone()) {
     config_.SetSupportHandshakeDone();
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 909a9f1..fad4082 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -2219,6 +2219,17 @@
   session_.OnStreamFrame(frame);
 }
 
+TEST_P(QuicSessionTestClient, MinAckDelaySetOnTheClientQuicConfig) {
+  if (!session_.version().HasIetfQuicFrames()) {
+    return;
+  }
+  session_.config()->SetClientConnectionOptions({kAFFE});
+  session_.Initialize();
+  ASSERT_EQ(session_.config()->GetMinAckDelayToSendMs(),
+            kDefaultMinAckDelayTimeMs);
+  ASSERT_TRUE(session_.connection()->can_receive_ack_frequency_frame());
+}
+
 TEST_P(QuicSessionTestClient, FailedToCreateStreamIfTooCloseToIdleTimeout) {
   connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
   EXPECT_TRUE(session_.CanOpenNextOutgoingBidirectionalStream());
diff --git a/quic/core/uber_received_packet_manager.cc b/quic/core/uber_received_packet_manager.cc
index d672fb8..7b2b32f 100644
--- a/quic/core/uber_received_packet_manager.cc
+++ b/quic/core/uber_received_packet_manager.cc
@@ -214,20 +214,20 @@
   }
 }
 
-void UberReceivedPacketManager::set_max_ack_delay(
-    QuicTime::Delta max_ack_delay) {
-  if (!supports_multiple_packet_number_spaces_) {
-    received_packet_managers_[0].set_local_max_ack_delay(max_ack_delay);
-    return;
-  }
-  received_packet_managers_[APPLICATION_DATA].set_local_max_ack_delay(
-      max_ack_delay);
-}
-
 void UberReceivedPacketManager::set_save_timestamps(bool save_timestamps) {
   for (auto& received_packet_manager : received_packet_managers_) {
     received_packet_manager.set_save_timestamps(save_timestamps);
   }
 }
 
+void UberReceivedPacketManager::OnAckFrequencyFrame(
+    const QuicAckFrequencyFrame& frame) {
+  if (!supports_multiple_packet_number_spaces_) {
+    QUIC_BUG << "Received AckFrequencyFrame when multiple packet number spaces "
+                "is not supported";
+    return;
+  }
+  received_packet_managers_[APPLICATION_DATA].OnAckFrequencyFrame(frame);
+}
+
 }  // namespace quic
diff --git a/quic/core/uber_received_packet_manager.h b/quic/core/uber_received_packet_manager.h
index a3c0877..17b5e26 100644
--- a/quic/core/uber_received_packet_manager.h
+++ b/quic/core/uber_received_packet_manager.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_
 #define QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_
 
+#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h"
 #include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
 
 namespace quic {
@@ -89,8 +90,7 @@
 
   void set_max_ack_ranges(size_t max_ack_ranges);
 
-  // Set the max ack delay to use for application data.
-  void set_max_ack_delay(QuicTime::Delta max_ack_delay);
+  void OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame);
 
   void set_save_timestamps(bool save_timestamps);
 
diff --git a/quic/core/uber_received_packet_manager_test.cc b/quic/core/uber_received_packet_manager_test.cc
index d4815a2..b7063d2 100644
--- a/quic/core/uber_received_packet_manager_test.cc
+++ b/quic/core/uber_received_packet_manager_test.cc
@@ -332,20 +332,6 @@
   CheckAckTimeout(clock_.ApproximateNow());
 }
 
-TEST_F(UberReceivedPacketManagerTest, SendDelayedMaxAckDelay) {
-  EXPECT_FALSE(HasPendingAck());
-  QuicTime::Delta max_ack_delay = QuicTime::Delta::FromMilliseconds(100);
-  manager_->set_max_ack_delay(max_ack_delay);
-  QuicTime ack_time = clock_.ApproximateNow() + max_ack_delay;
-
-  RecordPacketReceipt(1, clock_.ApproximateNow());
-  MaybeUpdateAckTimeout(kInstigateAck, 1);
-  CheckAckTimeout(ack_time);
-  // Simulate delayed ack alarm firing.
-  clock_.AdvanceTime(max_ack_delay);
-  CheckAckTimeout(clock_.ApproximateNow());
-}
-
 TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) {
   EXPECT_FALSE(HasPendingAck());
   // The ack time should be based on min_rtt * 1/4, since it's less than the