Always send the earliest ack in quicconnection::sendallpendingacks. protected by gfe2_reloadable_flag_quic_always_send_earliest_ack.

PiperOrigin-RevId: 313445668
Change-Id: Ibb17ff261f40d9da52f5e5e043e496daac6829ea
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index d39aa1e..36dea57 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -4001,21 +4001,27 @@
   DCHECK(SupportsMultiplePacketNumberSpaces());
   QUIC_DVLOG(1) << ENDPOINT << "Trying to send all pending ACKs";
   ack_alarm_->Cancel();
+  const QuicTime earliest_ack_timeout =
+      uber_received_packet_manager_.GetEarliestAckTimeout();
+  QUIC_BUG_IF(!earliest_ack_timeout.IsInitialized());
   // Latches current encryption level.
   const EncryptionLevel current_encryption_level = encryption_level_;
   for (int8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) {
     const QuicTime ack_timeout = uber_received_packet_manager_.GetAckTimeout(
         static_cast<PacketNumberSpace>(i));
-    if (!ack_timeout.IsInitialized() ||
-        ack_timeout > clock_->ApproximateNow()) {
+    if (!ack_timeout.IsInitialized()) {
       continue;
     }
-    if (!framer_.HasEncrypterOfEncryptionLevel(
-            QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)))) {
-      QUIC_BUG << ENDPOINT << "Cannot send ACKs for packet number space "
-               << PacketNumberSpaceToString(static_cast<PacketNumberSpace>(i))
-               << " without corresponding encrypter";
-      continue;
+    if (ack_timeout > clock_->ApproximateNow()) {
+      if (!GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+        continue;
+      }
+      QUIC_RELOADABLE_FLAG_COUNT(quic_always_send_earliest_ack);
+      if (ack_timeout > earliest_ack_timeout) {
+        // Always send the earliest ACK to make forward progress in case alarm
+        // fires early.
+        continue;
+      }
     }
     QUIC_DVLOG(1) << ENDPOINT << "Sending ACK of packet number space "
                   << PacketNumberSpaceToString(
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 714db95..a9e25f0 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -10715,6 +10715,52 @@
   }
 }
 
+TEST_P(QuicConnectionTest, AckAlarmFiresEarly) {
+  if (!connection_.SupportsMultiplePacketNumberSpaces()) {
+    return;
+  }
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  if (QuicVersionUsesCryptoFrames(connection_.transport_version())) {
+    EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
+  }
+  EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber());
+  use_tagging_decrypter();
+  // Receives packet 1000 in initial data.
+  ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+
+  peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT,
+                            std::make_unique<TaggingEncrypter>(0x02));
+  SetDecrypter(ENCRYPTION_ZERO_RTT,
+               std::make_unique<StrictTaggingDecrypter>(0x02));
+  connection_.SetEncrypter(ENCRYPTION_INITIAL,
+                           std::make_unique<TaggingEncrypter>(0x02));
+  // Receives packet 1000 in application data.
+  ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT);
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+  // Verify ACK deadline does not change.
+  EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity,
+            connection_.GetAckAlarm()->deadline());
+
+  // Ack alarm fires early.
+  if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+    // Verify the earliest ACK is flushed.
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+  } else {
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+  }
+  connection_.GetAckAlarm()->Fire();
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+  if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) {
+    EXPECT_EQ(clock_.ApproximateNow() + DefaultDelayedAckTime(),
+              connection_.GetAckAlarm()->deadline());
+  } else {
+    // No forward progress has been made.
+    EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity,
+              connection_.GetAckAlarm()->deadline());
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic