gfe-relnote: In QUIC, add uber_received_packet_manager which purely wraps a received_packet_manager. Using it is protected by gfe2_reloadable_flag_quic_use_uber_received_packet_manager.

PiperOrigin-RevId: 239601171
Change-Id: Iaa62e2641e0466a03981a6ba7dd128990b09744c
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 574dd0c..f213d35 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -266,6 +266,7 @@
           ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
       close_connection_after_five_rtos_(false),
       received_packet_manager_(&stats_),
+      uber_received_packet_manager_(&stats_),
       ack_queued_(false),
       num_retransmittable_packets_received_since_last_ack_sent_(0),
       num_packets_received_since_last_ack_sent_(0),
@@ -353,7 +354,10 @@
           GetQuicReloadableFlag(quic_fix_termination_packets)),
       send_ack_when_on_can_write_(false),
       validate_packet_number_post_decryption_(
-          GetQuicReloadableFlag(quic_validate_packet_number_post_decryption)) {
+          GetQuicReloadableFlag(quic_validate_packet_number_post_decryption)),
+      use_uber_received_packet_manager_(
+          received_packet_manager_.decide_when_to_send_acks() &&
+          GetQuicReloadableFlag(quic_use_uber_received_packet_manager)) {
   if (ack_mode_ == ACK_DECIMATION) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_enable_ack_decimation);
   }
@@ -370,6 +374,9 @@
   if (validate_packet_number_post_decryption_) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_validate_packet_number_post_decryption);
   }
+  if (use_uber_received_packet_manager_) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_use_uber_received_packet_manager);
+  }
   QUIC_DLOG(INFO) << ENDPOINT
                   << "Created connection with connection_id: " << connection_id
                   << " and version: "
@@ -396,7 +403,11 @@
   SetMaxPacketLength(perspective_ == Perspective::IS_SERVER
                          ? kDefaultServerMaxPacketSize
                          : kDefaultMaxPacketSize);
-  received_packet_manager_.set_max_ack_ranges(255);
+  if (use_uber_received_packet_manager_) {
+    uber_received_packet_manager_.set_max_ack_ranges(255);
+  } else {
+    received_packet_manager_.set_max_ack_ranges(255);
+  }
   MaybeEnableSessionDecidesWhatToWrite();
   DCHECK(!GetQuicRestartFlag(quic_no_server_conn_ver_negotiation2) ||
          perspective_ == Perspective::IS_CLIENT ||
@@ -452,7 +463,11 @@
     debug_visitor_->OnSetFromConfig(config);
   }
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    received_packet_manager_.SetFromConfig(config, perspective_);
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.SetFromConfig(config, perspective_);
+    } else {
+      received_packet_manager_.SetFromConfig(config, perspective_);
+    }
   } else {
     if (GetQuicReloadableFlag(quic_enable_ack_decimation) &&
         config.HasClientSentConnectionOption(kACD0, perspective_)) {
@@ -493,7 +508,11 @@
       config.HasClientSentConnectionOption(kSTMP, perspective_)) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_send_timestamps);
     framer_.set_process_timestamps(true);
-    received_packet_manager_.set_save_timestamps(true);
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.set_save_timestamps(true);
+    } else {
+      received_packet_manager_.set_save_timestamps(true);
+    }
   }
 
   supports_release_time_ =
@@ -802,21 +821,27 @@
 
   // If this packet has already been seen, or the sender has told us that it
   // will not be retransmitted, then stop processing the packet.
-  if (!validate_packet_number_post_decryption_ &&
-      !received_packet_manager_.IsAwaitingPacket(header.packet_number)) {
-    if (framer_.IsIetfStatelessResetPacket(header)) {
-      QuicIetfStatelessResetPacket packet(
-          header, header.possible_stateless_reset_token);
-      OnAuthenticatedIetfStatelessResetPacket(packet);
+  if (!validate_packet_number_post_decryption_) {
+    const bool is_awaiting =
+        use_uber_received_packet_manager_
+            ? uber_received_packet_manager_.IsAwaitingPacket(
+                  header.packet_number)
+            : received_packet_manager_.IsAwaitingPacket(header.packet_number);
+    if (!is_awaiting) {
+      if (framer_.IsIetfStatelessResetPacket(header)) {
+        QuicIetfStatelessResetPacket packet(
+            header, header.possible_stateless_reset_token);
+        OnAuthenticatedIetfStatelessResetPacket(packet);
+        return false;
+      }
+      QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number
+                      << " no longer being waited for.  Discarding.";
+      if (debug_visitor_ != nullptr) {
+        debug_visitor_->OnDuplicatePacket(header.packet_number);
+      }
+      ++stats_.packets_dropped;
       return false;
     }
-    QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number
-                    << " no longer being waited for.  Discarding.";
-    if (debug_visitor_ != nullptr) {
-      debug_visitor_->OnDuplicatePacket(header.packet_number);
-    }
-    ++stats_.packets_dropped;
-    return false;
   }
 
   if (version_negotiation_state_ != NEGOTIATED_VERSION &&
@@ -925,13 +950,20 @@
   QUIC_DVLOG(1) << ENDPOINT << "Received packet header: " << header;
   last_header_ = header;
   // An ack will be sent if a missing retransmittable packet was received;
-  was_last_packet_missing_ =
-      received_packet_manager_.IsMissing(last_header_.packet_number);
+  if (!use_uber_received_packet_manager_) {
+    was_last_packet_missing_ =
+        received_packet_manager_.IsMissing(last_header_.packet_number);
+  }
 
   // Record packet receipt to populate ack info before processing stream
   // frames, since the processing may result in sending a bundled ack.
-  received_packet_manager_.RecordPacketReceived(last_header_,
-                                                time_of_last_received_packet_);
+  if (use_uber_received_packet_manager_) {
+    uber_received_packet_manager_.RecordPacketReceived(
+        last_header_, time_of_last_received_packet_);
+  } else {
+    received_packet_manager_.RecordPacketReceived(
+        last_header_, time_of_last_received_packet_);
+  }
   DCHECK(connected_);
   return true;
 }
@@ -958,8 +990,8 @@
     QUIC_PEER_BUG << ENDPOINT
                   << "Received an unencrypted data frame: closing connection"
                   << " packet_number:" << last_header_.packet_number
-                  << " stream_id:" << frame.stream_id << " received_packets:"
-                  << received_packet_manager_.ack_frame();
+                  << " stream_id:" << frame.stream_id
+                  << " received_packets:" << GetUpdatedAckFrame();
     CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA,
                     "Unencrypted stream data seen.",
                     ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
@@ -1134,7 +1166,11 @@
   }
 
   largest_seen_packet_with_stop_waiting_ = last_header_.packet_number;
-  received_packet_manager_.DontWaitForPacketsBefore(frame.least_unacked);
+  if (use_uber_received_packet_manager_) {
+    uber_received_packet_manager_.DontWaitForPacketsBefore(frame.least_unacked);
+  } else {
+    received_packet_manager_.DontWaitForPacketsBefore(frame.least_unacked);
+  }
   return connected_;
 }
 
@@ -1161,14 +1197,15 @@
 
 const char* QuicConnection::ValidateStopWaitingFrame(
     const QuicStopWaitingFrame& stop_waiting) {
-  if (received_packet_manager_.peer_least_packet_awaiting_ack()
-          .IsInitialized() &&
-      stop_waiting.least_unacked <
-          received_packet_manager_.peer_least_packet_awaiting_ack()) {
-    QUIC_DLOG(ERROR)
-        << ENDPOINT
-        << "Peer's sent low least_unacked: " << stop_waiting.least_unacked
-        << " vs " << received_packet_manager_.peer_least_packet_awaiting_ack();
+  const QuicPacketNumber peer_least_packet_awaiting_ack =
+      use_uber_received_packet_manager_
+          ? uber_received_packet_manager_.peer_least_packet_awaiting_ack()
+          : received_packet_manager_.peer_least_packet_awaiting_ack();
+  if (peer_least_packet_awaiting_ack.IsInitialized() &&
+      stop_waiting.least_unacked < peer_least_packet_awaiting_ack) {
+    QUIC_DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
+                     << stop_waiting.least_unacked << " vs "
+                     << peer_least_packet_awaiting_ack;
     // We never process old ack frames, so this number should only increase.
     return "Least unacked too small.";
   }
@@ -1451,11 +1488,19 @@
       should_last_packet_instigate_acks_ && was_last_packet_missing_;
 
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    received_packet_manager_.MaybeUpdateAckTimeout(
-        should_last_packet_instigate_acks_, last_header_.packet_number,
-        time_of_last_received_packet_, clock_->ApproximateNow(),
-        sent_packet_manager_.GetRttStats(),
-        sent_packet_manager_.delayed_ack_time());
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.MaybeUpdateAckTimeout(
+          should_last_packet_instigate_acks_, last_header_.packet_number,
+          time_of_last_received_packet_, clock_->ApproximateNow(),
+          sent_packet_manager_.GetRttStats(),
+          sent_packet_manager_.delayed_ack_time());
+    } else {
+      received_packet_manager_.MaybeUpdateAckTimeout(
+          should_last_packet_instigate_acks_, last_header_.packet_number,
+          time_of_last_received_packet_, clock_->ApproximateNow(),
+          sent_packet_manager_.GetRttStats(),
+          sent_packet_manager_.delayed_ack_time());
+    }
   } else if (ack_frame_updated()) {
     // It's possible the ack frame was sent along with response data, so it
     // no longer needs to be sent.
@@ -1609,6 +1654,10 @@
 }
 
 const QuicFrame QuicConnection::GetUpdatedAckFrame() {
+  if (use_uber_received_packet_manager_) {
+    return uber_received_packet_manager_.GetUpdatedAckFrame(
+        clock_->ApproximateNow());
+  }
   return received_packet_manager_.GetUpdatedAckFrame(clock_->ApproximateNow());
 }
 
@@ -1910,7 +1959,10 @@
 
   WriteQueuedPackets();
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    const QuicTime ack_timeout = received_packet_manager_.ack_timeout();
+    const QuicTime ack_timeout =
+        use_uber_received_packet_manager_
+            ? uber_received_packet_manager_.GetAckTimeout()
+            : received_packet_manager_.ack_timeout();
     if (ack_timeout.IsInitialized() &&
         ack_timeout <= clock_->ApproximateNow()) {
       // Send an ACK now because either 1) we were write blocked when we last
@@ -2033,14 +2085,19 @@
 
 bool QuicConnection::ValidateReceivedPacketNumber(
     QuicPacketNumber packet_number) {
-  if (validate_packet_number_post_decryption_ &&
-      !received_packet_manager_.IsAwaitingPacket(packet_number)) {
-    QUIC_DLOG(INFO) << ENDPOINT << "Packet " << packet_number
-                    << " no longer being waited for.  Discarding.";
-    if (debug_visitor_ != nullptr) {
-      debug_visitor_->OnDuplicatePacket(packet_number);
+  if (validate_packet_number_post_decryption_) {
+    const bool is_awaiting =
+        use_uber_received_packet_manager_
+            ? uber_received_packet_manager_.IsAwaitingPacket(packet_number)
+            : received_packet_manager_.IsAwaitingPacket(packet_number);
+    if (!is_awaiting) {
+      QUIC_DLOG(INFO) << ENDPOINT << "Packet " << packet_number
+                      << " no longer being waited for.  Discarding.";
+      if (debug_visitor_ != nullptr) {
+        debug_visitor_->OnDuplicatePacket(packet_number);
+      }
+      return false;
     }
-    return false;
   }
 
   if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
@@ -2064,17 +2121,18 @@
     }
     return true;
   }
-
-  if (packet_number > received_packet_manager_.PeerFirstSendingPacketNumber() &&
+  const QuicPacketNumber peer_first_sending_packet_number =
+      use_uber_received_packet_manager_
+          ? uber_received_packet_manager_.PeerFirstSendingPacketNumber()
+          : received_packet_manager_.PeerFirstSendingPacketNumber();
+  if (packet_number > peer_first_sending_packet_number &&
       packet_number <= MaxRandomInitialPacketNumber()) {
     QUIC_CODE_COUNT_N(had_possibly_random_ipn, 2, 2);
   }
   const bool out_of_bound =
       last_header_.packet_number.IsInitialized()
           ? !Near(packet_number, last_header_.packet_number)
-          : packet_number >=
-                (received_packet_manager_.PeerFirstSendingPacketNumber() +
-                 kMaxPacketGap);
+          : packet_number >= (peer_first_sending_packet_number + kMaxPacketGap);
   if (!out_of_bound) {
     return true;
   }
@@ -2213,7 +2271,12 @@
   QuicFrames frames;
   bool has_pending_ack = false;
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    has_pending_ack = received_packet_manager_.ack_timeout().IsInitialized();
+    if (use_uber_received_packet_manager_) {
+      has_pending_ack =
+          uber_received_packet_manager_.GetAckTimeout().IsInitialized();
+    } else {
+      has_pending_ack = received_packet_manager_.ack_timeout().IsInitialized();
+    }
   } else {
     has_pending_ack = ack_alarm_->IsSet();
   }
@@ -3207,7 +3270,9 @@
     if (connection_->packet_generator_.deprecate_ack_bundling_mode()) {
       if (connection_->received_packet_manager_.decide_when_to_send_acks()) {
         const QuicTime ack_timeout =
-            connection_->received_packet_manager_.ack_timeout();
+            connection_->use_uber_received_packet_manager_
+                ? connection_->uber_received_packet_manager_.GetAckTimeout()
+                : connection_->received_packet_manager_.ack_timeout();
         if (ack_timeout.IsInitialized()) {
           if (ack_timeout <= connection_->clock_->ApproximateNow() &&
               !connection_->CanWrite(NO_RETRANSMITTABLE_DATA)) {
@@ -3531,6 +3596,9 @@
 }
 
 bool QuicConnection::ack_frame_updated() const {
+  if (use_uber_received_packet_manager_) {
+    return uber_received_packet_manager_.AckFrameUpdated();
+  }
   return received_packet_manager_.ack_frame_updated();
 }
 
@@ -3676,8 +3744,13 @@
 void QuicConnection::PostProcessAfterAckFrame(bool send_stop_waiting,
                                               bool acked_new_packet) {
   if (no_stop_waiting_frames_) {
-    received_packet_manager_.DontWaitForPacketsBefore(
-        sent_packet_manager_.largest_packet_peer_knows_is_acked());
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.DontWaitForPacketsBefore(
+          sent_packet_manager_.largest_packet_peer_knows_is_acked());
+    } else {
+      received_packet_manager_.DontWaitForPacketsBefore(
+          sent_packet_manager_.largest_packet_peer_knows_is_acked());
+    }
   }
   // Always reset the retransmission alarm when an ack comes in, since we now
   // have a better estimate of the current rtt than when it was set.
@@ -3744,7 +3817,11 @@
   num_retransmittable_packets_received_since_last_ack_sent_ = 0;
   num_packets_received_since_last_ack_sent_ = 0;
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    received_packet_manager_.ResetAckStates();
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.ResetAckStates();
+    } else {
+      received_packet_manager_.ResetAckStates();
+    }
   }
 }
 
@@ -3827,11 +3904,17 @@
 }
 
 QuicPacketNumber QuicConnection::GetLargestReceivedPacket() const {
+  if (use_uber_received_packet_manager_) {
+    return uber_received_packet_manager_.GetLargestObserved();
+  }
   return received_packet_manager_.GetLargestObserved();
 }
 
 size_t QuicConnection::min_received_before_ack_decimation() const {
   if (received_packet_manager_.decide_when_to_send_acks()) {
+    if (use_uber_received_packet_manager_) {
+      return uber_received_packet_manager_.min_received_before_ack_decimation();
+    }
     return received_packet_manager_.min_received_before_ack_decimation();
   }
   return min_received_before_ack_decimation_;
@@ -3839,7 +3922,13 @@
 
 void QuicConnection::set_min_received_before_ack_decimation(size_t new_value) {
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    received_packet_manager_.set_min_received_before_ack_decimation(new_value);
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.set_min_received_before_ack_decimation(
+          new_value);
+    } else {
+      received_packet_manager_.set_min_received_before_ack_decimation(
+          new_value);
+    }
   } else {
     min_received_before_ack_decimation_ = new_value;
   }
@@ -3847,6 +3936,10 @@
 
 size_t QuicConnection::ack_frequency_before_ack_decimation() const {
   if (received_packet_manager_.decide_when_to_send_acks()) {
+    if (use_uber_received_packet_manager_) {
+      return uber_received_packet_manager_
+          .ack_frequency_before_ack_decimation();
+    }
     return received_packet_manager_.ack_frequency_before_ack_decimation();
   }
   return ack_frequency_before_ack_decimation_;
@@ -3855,7 +3948,13 @@
 void QuicConnection::set_ack_frequency_before_ack_decimation(size_t new_value) {
   DCHECK_GT(new_value, 0u);
   if (received_packet_manager_.decide_when_to_send_acks()) {
-    received_packet_manager_.set_ack_frequency_before_ack_decimation(new_value);
+    if (use_uber_received_packet_manager_) {
+      uber_received_packet_manager_.set_ack_frequency_before_ack_decimation(
+          new_value);
+    } else {
+      received_packet_manager_.set_ack_frequency_before_ack_decimation(
+          new_value);
+    }
   } else {
     ack_frequency_before_ack_decimation_ = new_value;
   }
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index ae9d5c3..745991f 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -38,10 +38,10 @@
 #include "net/third_party/quiche/src/quic/core/quic_packet_generator.h"
 #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
-#include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_time.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -1236,7 +1236,11 @@
   // 200ms, this is over 5 seconds.
   bool close_connection_after_five_rtos_;
 
+  // TODO(fayang): remove received_packet_manager_ when deprecating
+  // quic_use_uber_received_packet_manager.
   QuicReceivedPacketManager received_packet_manager_;
+  // Used when use_uber_received_packet_manager_ is true.
+  UberReceivedPacketManager uber_received_packet_manager_;
 
   // Indicates whether an ack should be sent the next time we try to write.
   // TODO(fayang): Remove ack_queued_ when deprecating
@@ -1487,6 +1491,10 @@
 
   // Latched value of quic_validate_packet_number_post_decryption.
   const bool validate_packet_number_post_decryption_;
+
+  // Latched value of quic_rpm_decides_when_to_send_acks and
+  // quic_use_uber_received_packet_manager.
+  const bool use_uber_received_packet_manager_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index 921c674..82984eb 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -154,7 +154,7 @@
 }
 
 bool QuicReceivedPacketManager::IsAwaitingPacket(
-    QuicPacketNumber packet_number) {
+    QuicPacketNumber packet_number) const {
   return quic::IsAwaitingPacket(ack_frame_, packet_number,
                                 peer_least_packet_awaiting_ack_);
 }
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h
index 787e1fb..8eb8cac 100644
--- a/quic/core/quic_received_packet_manager.h
+++ b/quic/core/quic_received_packet_manager.h
@@ -17,6 +17,7 @@
 namespace test {
 class QuicConnectionPeer;
 class QuicReceivedPacketManagerPeer;
+class UberReceivedPacketManagerPeer;
 }  // namespace test
 
 struct QuicConnectionStats;
@@ -42,7 +43,7 @@
   virtual bool IsMissing(QuicPacketNumber packet_number);
 
   // Checks if we're still waiting for the packet with |packet_number|.
-  virtual bool IsAwaitingPacket(QuicPacketNumber packet_number);
+  virtual bool IsAwaitingPacket(QuicPacketNumber packet_number) const;
 
   // Retrieves a frame containing a QuicAckFrame.  The ack frame may not be
   // changed outside QuicReceivedPacketManager and must be serialized before
@@ -75,7 +76,7 @@
   // packets of the largest observed.
   virtual bool HasNewMissingPackets() const;
 
-  QuicPacketNumber peer_least_packet_awaiting_ack() {
+  QuicPacketNumber peer_least_packet_awaiting_ack() const {
     return peer_least_packet_awaiting_ack_;
   }
 
@@ -123,6 +124,7 @@
  private:
   friend class test::QuicConnectionPeer;
   friend class test::QuicReceivedPacketManagerPeer;
+  friend class test::UberReceivedPacketManagerPeer;
 
   // Sets ack_timeout_ to |time| if ack_timeout_ is not initialized or > time.
   void MaybeUpdateAckTimeoutTo(QuicTime time);
diff --git a/quic/core/uber_received_packet_manager.cc b/quic/core/uber_received_packet_manager.cc
new file mode 100644
index 0000000..b730474
--- /dev/null
+++ b/quic/core/uber_received_packet_manager.cc
@@ -0,0 +1,108 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h"
+
+namespace quic {
+
+UberReceivedPacketManager::UberReceivedPacketManager(QuicConnectionStats* stats)
+    : received_packet_manager_(stats) {}
+
+UberReceivedPacketManager::~UberReceivedPacketManager() {}
+
+void UberReceivedPacketManager::SetFromConfig(const QuicConfig& config,
+                                              Perspective perspective) {
+  received_packet_manager_.SetFromConfig(config, perspective);
+}
+
+bool UberReceivedPacketManager::IsAwaitingPacket(
+    QuicPacketNumber packet_number) const {
+  return received_packet_manager_.IsAwaitingPacket(packet_number);
+}
+
+const QuicFrame UberReceivedPacketManager::GetUpdatedAckFrame(
+    QuicTime approximate_now) {
+  return received_packet_manager_.GetUpdatedAckFrame(approximate_now);
+}
+
+void UberReceivedPacketManager::RecordPacketReceived(
+    const QuicPacketHeader& header,
+    QuicTime receipt_time) {
+  received_packet_manager_.RecordPacketReceived(header, receipt_time);
+}
+
+void UberReceivedPacketManager::DontWaitForPacketsBefore(
+    QuicPacketNumber least_unacked) {
+  received_packet_manager_.DontWaitForPacketsBefore(least_unacked);
+}
+
+void UberReceivedPacketManager::MaybeUpdateAckTimeout(
+    bool should_last_packet_instigate_acks,
+    QuicPacketNumber last_received_packet_number,
+    QuicTime time_of_last_received_packet,
+    QuicTime now,
+    const RttStats* rtt_stats,
+    QuicTime::Delta delayed_ack_time) {
+  received_packet_manager_.MaybeUpdateAckTimeout(
+      should_last_packet_instigate_acks, last_received_packet_number,
+      time_of_last_received_packet, now, rtt_stats, delayed_ack_time);
+}
+
+void UberReceivedPacketManager::ResetAckStates() {
+  received_packet_manager_.ResetAckStates();
+}
+
+bool UberReceivedPacketManager::AckFrameUpdated() const {
+  return received_packet_manager_.ack_frame_updated();
+}
+
+QuicPacketNumber UberReceivedPacketManager::GetLargestObserved() const {
+  return received_packet_manager_.GetLargestObserved();
+}
+
+QuicTime UberReceivedPacketManager::GetAckTimeout() const {
+  return received_packet_manager_.ack_timeout();
+}
+
+QuicPacketNumber UberReceivedPacketManager::PeerFirstSendingPacketNumber()
+    const {
+  return received_packet_manager_.PeerFirstSendingPacketNumber();
+}
+
+QuicPacketNumber UberReceivedPacketManager::peer_least_packet_awaiting_ack()
+    const {
+  return received_packet_manager_.peer_least_packet_awaiting_ack();
+}
+
+size_t UberReceivedPacketManager::min_received_before_ack_decimation() const {
+  return received_packet_manager_.min_received_before_ack_decimation();
+}
+
+void UberReceivedPacketManager::set_min_received_before_ack_decimation(
+    size_t new_value) {
+  received_packet_manager_.set_min_received_before_ack_decimation(new_value);
+}
+
+size_t UberReceivedPacketManager::ack_frequency_before_ack_decimation() const {
+  return received_packet_manager_.ack_frequency_before_ack_decimation();
+}
+
+void UberReceivedPacketManager::set_ack_frequency_before_ack_decimation(
+    size_t new_value) {
+  received_packet_manager_.set_ack_frequency_before_ack_decimation(new_value);
+}
+
+const QuicAckFrame& UberReceivedPacketManager::ack_frame() const {
+  return received_packet_manager_.ack_frame();
+}
+
+void UberReceivedPacketManager::set_max_ack_ranges(size_t max_ack_ranges) {
+  received_packet_manager_.set_max_ack_ranges(max_ack_ranges);
+}
+
+void UberReceivedPacketManager::set_save_timestamps(bool save_timestamps) {
+  received_packet_manager_.set_save_timestamps(save_timestamps);
+}
+
+}  // namespace quic
diff --git a/quic/core/uber_received_packet_manager.h b/quic/core/uber_received_packet_manager.h
new file mode 100644
index 0000000..367a7c0
--- /dev/null
+++ b/quic/core/uber_received_packet_manager.h
@@ -0,0 +1,87 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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/quic_received_packet_manager.h"
+
+namespace quic {
+
+// This class simply wraps a single received packet manager.
+class QUIC_EXPORT_PRIVATE UberReceivedPacketManager {
+ public:
+  explicit UberReceivedPacketManager(QuicConnectionStats* stats);
+  UberReceivedPacketManager(const UberReceivedPacketManager&) = delete;
+  UberReceivedPacketManager& operator=(const UberReceivedPacketManager&) =
+      delete;
+  virtual ~UberReceivedPacketManager();
+
+  void SetFromConfig(const QuicConfig& config, Perspective perspective);
+
+  // Checks if we are still waiting for the packet with |packet_number|.
+  bool IsAwaitingPacket(QuicPacketNumber packet_number) const;
+
+  // Called after a packet has been successfully decrypted and its header has
+  // been parsed.
+  void RecordPacketReceived(const QuicPacketHeader& header,
+                            QuicTime receipt_time);
+
+  // Retrieves a frame containing a QuicAckFrame. The ack frame must be
+  // serialized before another packet is received, or it will change.
+  const QuicFrame GetUpdatedAckFrame(QuicTime approximate_now);
+
+  // Stop ACKing packets before |least_unacked|.
+  void DontWaitForPacketsBefore(QuicPacketNumber least_unacked);
+
+  // Called after header of last received packet has been successfully processed
+  // to update ACK timeout.
+  void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks,
+                             QuicPacketNumber last_received_packet_number,
+                             QuicTime time_of_last_received_packet,
+                             QuicTime now,
+                             const RttStats* rtt_stats,
+                             QuicTime::Delta delayed_ack_time);
+
+  // Resets ACK related states, called after an ACK is successfully sent.
+  void ResetAckStates();
+
+  // Returns true if ACK frame has been updated since GetUpdatedAckFrame was
+  // last called.
+  bool AckFrameUpdated() const;
+
+  // Returns the largest received packet number.
+  QuicPacketNumber GetLargestObserved() const;
+
+  // Returns current ACK timeout.
+  QuicTime GetAckTimeout() const;
+
+  // Returns peer first sending packet number to our best knowledge.
+  QuicPacketNumber PeerFirstSendingPacketNumber() const;
+
+  QuicPacketNumber peer_least_packet_awaiting_ack() const;
+
+  size_t min_received_before_ack_decimation() const;
+  void set_min_received_before_ack_decimation(size_t new_value);
+
+  size_t ack_frequency_before_ack_decimation() const;
+  void set_ack_frequency_before_ack_decimation(size_t new_value);
+
+  // For logging purposes.
+  const QuicAckFrame& ack_frame() const;
+
+  void set_max_ack_ranges(size_t max_ack_ranges);
+
+  void set_save_timestamps(bool save_timestamps);
+
+ private:
+  friend class test::QuicConnectionPeer;
+  friend class test::UberReceivedPacketManagerPeer;
+
+  QuicReceivedPacketManager received_packet_manager_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_
diff --git a/quic/core/uber_received_packet_manager_test.cc b/quic/core/uber_received_packet_manager_test.cc
new file mode 100644
index 0000000..4ffb03c
--- /dev/null
+++ b/quic/core/uber_received_packet_manager_test.cc
@@ -0,0 +1,690 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/uber_received_packet_manager.h"
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
+#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+
+namespace quic {
+namespace test {
+
+class UberReceivedPacketManagerPeer {
+ public:
+  static void SetAckMode(UberReceivedPacketManager* manager, AckMode ack_mode) {
+    manager->received_packet_manager_.ack_mode_ = ack_mode;
+  }
+
+  static void SetFastAckAfterQuiescence(UberReceivedPacketManager* manager,
+                                        bool fast_ack_after_quiescence) {
+    manager->received_packet_manager_.fast_ack_after_quiescence_ =
+        fast_ack_after_quiescence;
+  }
+
+  static void SetAckDecimationDelay(UberReceivedPacketManager* manager,
+                                    float ack_decimation_delay) {
+    manager->received_packet_manager_.ack_decimation_delay_ =
+        ack_decimation_delay;
+  }
+};
+
+namespace {
+
+const bool kInstigateAck = true;
+const QuicTime::Delta kMinRttMs = QuicTime::Delta::FromMilliseconds(40);
+const QuicTime::Delta kDelayedAckTime =
+    QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs);
+
+class UberReceivedPacketManagerTest : public QuicTest {
+ protected:
+  UberReceivedPacketManagerTest() {
+    SetQuicReloadableFlag(quic_deprecate_ack_bundling_mode, true);
+    SetQuicReloadableFlag(quic_rpm_decides_when_to_send_acks, true);
+    manager_ = QuicMakeUnique<UberReceivedPacketManager>(&stats_);
+    clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+    rtt_stats_.UpdateRtt(kMinRttMs, QuicTime::Delta::Zero(), QuicTime::Zero());
+    manager_->set_save_timestamps(true);
+  }
+
+  void RecordPacketReceipt(uint64_t packet_number) {
+    RecordPacketReceipt(packet_number, QuicTime::Zero());
+  }
+
+  void RecordPacketReceipt(uint64_t packet_number, QuicTime receipt_time) {
+    QuicPacketHeader header;
+    header.packet_number = QuicPacketNumber(packet_number);
+    manager_->RecordPacketReceived(header, receipt_time);
+  }
+
+  bool HasPendingAck() { return manager_->GetAckTimeout().IsInitialized(); }
+
+  void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks,
+                             uint64_t last_received_packet_number) {
+    manager_->MaybeUpdateAckTimeout(
+        should_last_packet_instigate_acks,
+        QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
+        clock_.ApproximateNow(), &rtt_stats_, kDelayedAckTime);
+  }
+
+  void CheckAckTimeout(QuicTime time) {
+    DCHECK(HasPendingAck() && manager_->GetAckTimeout() == time);
+    if (time <= clock_.ApproximateNow()) {
+      // ACK timeout expires, send an ACK.
+      manager_->ResetAckStates();
+      DCHECK(!HasPendingAck());
+    }
+  }
+
+  MockClock clock_;
+  RttStats rtt_stats_;
+  QuicConnectionStats stats_;
+  std::unique_ptr<UberReceivedPacketManager> manager_;
+};
+
+TEST_F(UberReceivedPacketManagerTest, DontWaitForPacketsBefore) {
+  QuicPacketHeader header;
+  header.packet_number = QuicPacketNumber(2u);
+  manager_->RecordPacketReceived(header, QuicTime::Zero());
+  header.packet_number = QuicPacketNumber(7u);
+  manager_->RecordPacketReceived(header, QuicTime::Zero());
+  EXPECT_TRUE(manager_->IsAwaitingPacket(QuicPacketNumber(3u)));
+  EXPECT_TRUE(manager_->IsAwaitingPacket(QuicPacketNumber(6u)));
+  manager_->DontWaitForPacketsBefore(QuicPacketNumber(4));
+  EXPECT_FALSE(manager_->IsAwaitingPacket(QuicPacketNumber(3u)));
+  EXPECT_TRUE(manager_->IsAwaitingPacket(QuicPacketNumber(6u)));
+}
+
+TEST_F(UberReceivedPacketManagerTest, GetUpdatedAckFrame) {
+  QuicPacketHeader header;
+  header.packet_number = QuicPacketNumber(2u);
+  QuicTime two_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  manager_->RecordPacketReceived(header, two_ms);
+  EXPECT_TRUE(manager_->AckFrameUpdated());
+
+  QuicFrame ack = manager_->GetUpdatedAckFrame(QuicTime::Zero());
+  manager_->ResetAckStates();
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  // When UpdateReceivedPacketInfo with a time earlier than the time of the
+  // largest observed packet, make sure that the delta is 0, not negative.
+  EXPECT_EQ(QuicTime::Delta::Zero(), ack.ack_frame->ack_delay_time);
+  EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
+
+  QuicTime four_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(4);
+  ack = manager_->GetUpdatedAckFrame(four_ms);
+  manager_->ResetAckStates();
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  // When UpdateReceivedPacketInfo after not having received a new packet,
+  // the delta should still be accurate.
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2),
+            ack.ack_frame->ack_delay_time);
+  // And received packet times won't have change.
+  EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
+
+  header.packet_number = QuicPacketNumber(999u);
+  manager_->RecordPacketReceived(header, two_ms);
+  header.packet_number = QuicPacketNumber(4u);
+  manager_->RecordPacketReceived(header, two_ms);
+  header.packet_number = QuicPacketNumber(1000u);
+  manager_->RecordPacketReceived(header, two_ms);
+  EXPECT_TRUE(manager_->AckFrameUpdated());
+  ack = manager_->GetUpdatedAckFrame(two_ms);
+  manager_->ResetAckStates();
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  // UpdateReceivedPacketInfo should discard any times which can't be
+  // expressed on the wire.
+  EXPECT_EQ(2u, ack.ack_frame->received_packet_times.size());
+}
+
+TEST_F(UberReceivedPacketManagerTest, UpdateReceivedConnectionStats) {
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  RecordPacketReceipt(1);
+  EXPECT_TRUE(manager_->AckFrameUpdated());
+  RecordPacketReceipt(6);
+  RecordPacketReceipt(2,
+                      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1));
+
+  EXPECT_EQ(4u, stats_.max_sequence_reordering);
+  EXPECT_EQ(1000, stats_.max_time_reordering_us);
+  EXPECT_EQ(1u, stats_.packets_reordered);
+}
+
+TEST_F(UberReceivedPacketManagerTest, LimitAckRanges) {
+  manager_->set_max_ack_ranges(10);
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  for (int i = 0; i < 100; ++i) {
+    RecordPacketReceipt(1 + 2 * i);
+    EXPECT_TRUE(manager_->AckFrameUpdated());
+    manager_->GetUpdatedAckFrame(QuicTime::Zero());
+    EXPECT_GE(10u, manager_->ack_frame().packets.NumIntervals());
+    EXPECT_EQ(QuicPacketNumber(1u + 2 * i),
+              manager_->ack_frame().packets.Max());
+    for (int j = 0; j < std::min(10, i + 1); ++j) {
+      ASSERT_GE(i, j);
+      EXPECT_TRUE(manager_->ack_frame().packets.Contains(
+          QuicPacketNumber(1 + (i - j) * 2)));
+      if (i > j) {
+        EXPECT_FALSE(manager_->ack_frame().packets.Contains(
+            QuicPacketNumber((i - j) * 2)));
+      }
+    }
+  }
+}
+
+TEST_F(UberReceivedPacketManagerTest, IgnoreOutOfOrderTimestamps) {
+  EXPECT_FALSE(manager_->AckFrameUpdated());
+  RecordPacketReceipt(1, QuicTime::Zero());
+  EXPECT_TRUE(manager_->AckFrameUpdated());
+  EXPECT_EQ(1u, manager_->ack_frame().received_packet_times.size());
+  RecordPacketReceipt(2,
+                      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1));
+  EXPECT_EQ(2u, manager_->ack_frame().received_packet_times.size());
+  RecordPacketReceipt(3, QuicTime::Zero());
+  EXPECT_EQ(2u, manager_->ack_frame().received_packet_times.size());
+}
+
+TEST_F(UberReceivedPacketManagerTest, OutOfOrderReceiptCausesAckSent) {
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(3, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 3);
+  if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) {
+    // Delayed ack is scheduled.
+    CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+  } else {
+    // Should ack immediately since we have missing packets.
+    CheckAckTimeout(clock_.ApproximateNow());
+  }
+
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 2);
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 1);
+  // Should ack immediately, since this fills the last hole.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(4, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 4);
+  // Delayed ack is scheduled.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+}
+
+TEST_F(UberReceivedPacketManagerTest, OutOfOrderAckReceiptCausesNoAck) {
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(!kInstigateAck, 2);
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(!kInstigateAck, 1);
+  EXPECT_FALSE(HasPendingAck());
+}
+
+TEST_F(UberReceivedPacketManagerTest, AckReceiptCausesAckSend) {
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(!kInstigateAck, 1);
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(!kInstigateAck, 2);
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(3, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 3);
+  // Delayed ack is scheduled.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+  clock_.AdvanceTime(kDelayedAckTime);
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(4, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(!kInstigateAck, 4);
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(5, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(!kInstigateAck, 5);
+  EXPECT_FALSE(HasPendingAck());
+}
+
+TEST_F(UberReceivedPacketManagerTest, AckSentEveryNthPacket) {
+  EXPECT_FALSE(HasPendingAck());
+  manager_->set_ack_frequency_before_ack_decimation(3);
+
+  // Receives packets 1 - 39.
+  for (size_t i = 1; i <= 39; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 3 == 0) {
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+}
+
+TEST_F(UberReceivedPacketManagerTest, AckDecimationReducesAcks) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
+                                            ACK_DECIMATION_WITH_REORDERING);
+
+  // Start ack decimation from 10th packet.
+  manager_->set_min_received_before_ack_decimation(10);
+
+  // Receives packets 1 - 29.
+  for (size_t i = 1; i <= 29; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i <= 10) {
+      // For packets 1-10, ack every 2 packets.
+      if (i % 2 == 0) {
+        CheckAckTimeout(clock_.ApproximateNow());
+      } else {
+        CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+      }
+      continue;
+    }
+    // ack at 20.
+    if (i == 20) {
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kMinRttMs * 0.25);
+    }
+  }
+
+  // We now receive the 30th packet, and so we send an ack.
+  RecordPacketReceipt(30, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 30);
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_F(UberReceivedPacketManagerTest, SendDelayedAfterQuiescence) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(),
+                                                           true);
+  // The beginning of the connection counts as quiescence.
+  QuicTime ack_time =
+      clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 1);
+  CheckAckTimeout(ack_time);
+  // Simulate delayed ack alarm firing.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // Process another packet immediately after sending the ack and expect the
+  // ack timeout to be set delayed ack time in the future.
+  ack_time = clock_.ApproximateNow() + kDelayedAckTime;
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 2);
+  CheckAckTimeout(ack_time);
+  // Simulate delayed ack alarm firing.
+  clock_.AdvanceTime(kDelayedAckTime);
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
+  RecordPacketReceipt(3, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 3);
+  CheckAckTimeout(ack_time);
+}
+
+TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
+  // The ack time should be based on min_rtt * 1/4, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
+
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  // The 10th received packet causes an ack to be sent.
+  for (uint64_t i = 1; i < 10; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
+  }
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_F(UberReceivedPacketManagerTest,
+       SendDelayedAckAckDecimationAfterQuiescence) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
+  UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(),
+                                                           true);
+  // The beginning of the connection counts as quiescence.
+  QuicTime ack_time =
+      clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 1);
+  CheckAckTimeout(ack_time);
+  // Simulate delayed ack alarm firing.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // Process another packet immedately after sending the ack and expect the
+  // ack timeout to be set delayed ack time in the future.
+  ack_time = clock_.ApproximateNow() + kDelayedAckTime;
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 2);
+  CheckAckTimeout(ack_time);
+  // Simulate delayed ack alarm firing.
+  clock_.AdvanceTime(kDelayedAckTime);
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
+  RecordPacketReceipt(3, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 3);
+  CheckAckTimeout(ack_time);
+  // Process enough packets to get into ack decimation behavior.
+  // The ack time should be based on min_rtt/4, since it's less than the
+  // default delayed ack time.
+  ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+  EXPECT_FALSE(HasPendingAck());
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  // The 10th received packet causes an ack to be sent.
+  for (uint64_t i = 1; i < 10; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
+  }
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // Wait 1 second and enesure the ack timeout is set to 1ms in the future.
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1);
+  RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
+  CheckAckTimeout(ack_time);
+}
+
+TEST_F(UberReceivedPacketManagerTest,
+       SendDelayedAckDecimationUnlimitedAggregation) {
+  EXPECT_FALSE(HasPendingAck());
+  QuicConfig config;
+  QuicTagVector connection_options;
+  connection_options.push_back(kACKD);
+  // No limit on the number of packets received before sending an ack.
+  connection_options.push_back(kAKDU);
+  config.SetConnectionOptionsToSend(connection_options);
+  manager_->SetFromConfig(config, Perspective::IS_CLIENT);
+
+  // The ack time should be based on min_rtt/4, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
+
+  // Process all the initial packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  // 18 packets will not cause an ack to be sent.  19 will because when
+  // stop waiting frames are in use, we ack every 20 packets no matter what.
+  for (int i = 1; i <= 18; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
+  }
+  CheckAckTimeout(ack_time);
+}
+
+TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION);
+  UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125);
+
+  // The ack time should be based on min_rtt/8, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
+
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  // The 10th received packet causes an ack to be sent.
+  for (uint64_t i = 1; i < 10; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
+  }
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
+                                            ACK_DECIMATION_WITH_REORDERING);
+
+  // The ack time should be based on min_rtt/4, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  // Receive one packet out of order and then the rest in order.
+  // The loop leaves a one packet gap between acks sent to simulate some loss.
+  for (int j = 0; j < 3; ++j) {
+    // Process packet 10 first and ensure the timeout is one eighth min_rtt.
+    RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11),
+                        clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11));
+    ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
+    CheckAckTimeout(ack_time);
+
+    // The 10th received packet causes an ack to be sent.
+    for (int i = 0; i < 9; ++i) {
+      RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11),
+                          clock_.ApproximateNow());
+      MaybeUpdateAckTimeout(kInstigateAck,
+                            kFirstDecimatedPacket + i + (j * 11));
+    }
+    CheckAckTimeout(clock_.ApproximateNow());
+  }
+}
+
+TEST_F(UberReceivedPacketManagerTest,
+       SendDelayedAckDecimationWithLargeReordering) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
+                                            ACK_DECIMATION_WITH_REORDERING);
+  // The ack time should be based on min_rtt/4, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25;
+
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19);
+  ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
+  CheckAckTimeout(ack_time);
+
+  // The 10th received packet causes an ack to be sent.
+  for (int i = 1; i < 9; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
+  }
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // The next packet received in order will cause an immediate ack, because it
+  // fills a hole.
+  RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_F(UberReceivedPacketManagerTest,
+       SendDelayedAckDecimationWithReorderingEighthRtt) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
+                                            ACK_DECIMATION_WITH_REORDERING);
+  UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125);
+  // The ack time should be based on min_rtt/8, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
+
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  // Process packet 10 first and ensure the timeout is one eighth min_rtt.
+  RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9);
+  CheckAckTimeout(ack_time);
+
+  // The 10th received packet causes an ack to be sent.
+  for (int i = 1; i < 9; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket);
+  }
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_F(UberReceivedPacketManagerTest,
+       SendDelayedAckDecimationWithLargeReorderingEighthRtt) {
+  EXPECT_FALSE(HasPendingAck());
+  UberReceivedPacketManagerPeer::SetAckMode(manager_.get(),
+                                            ACK_DECIMATION_WITH_REORDERING);
+  UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125);
+
+  // The ack time should be based on min_rtt/8, since it's less than the
+  // default delayed ack time.
+  QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125;
+  // Process all the packets in order so there aren't missing packets.
+  uint64_t kFirstDecimatedPacket = 101;
+  for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) {
+    RecordPacketReceipt(i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, i);
+    if (i % 2 == 0) {
+      // Ack every 2 packets by default.
+      CheckAckTimeout(clock_.ApproximateNow());
+    } else {
+      CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+    }
+  }
+
+  RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket);
+  CheckAckTimeout(ack_time);
+
+  RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19);
+  CheckAckTimeout(ack_time);
+
+  // The 10th received packet causes an ack to be sent.
+  for (int i = 1; i < 9; ++i) {
+    RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow());
+    MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i);
+  }
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  // The next packet received in order will cause an immediate ack, because it
+  // fills a hole.
+  RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10);
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace quic