Reporting ACK delay based on packet receipt time (rather than packet process time).

Protected by FLAGS_quic_reloadable_flag_quic_update_ack_timeout_on_receipt_time.

PiperOrigin-RevId: 436708428
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index f59e250..99441b6 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2199,8 +2199,8 @@
   if (!should_last_packet_instigate_acks_) {
     uber_received_packet_manager_.MaybeUpdateAckTimeout(
         should_last_packet_instigate_acks_, last_decrypted_packet_level_,
-        last_header_.packet_number, clock_->ApproximateNow(),
-        sent_packet_manager_.GetRttStats());
+        last_header_.packet_number, last_received_packet_info_.receipt_time,
+        clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
   }
 
   ClearLastFrames();
@@ -6330,8 +6330,8 @@
   should_last_packet_instigate_acks_ = true;
   uber_received_packet_manager_.MaybeUpdateAckTimeout(
       /*should_last_packet_instigate_acks=*/true, last_decrypted_packet_level_,
-      last_header_.packet_number, clock_->ApproximateNow(),
-      sent_packet_manager_.GetRttStats());
+      last_header_.packet_number, last_received_packet_info_.receipt_time,
+      clock_->ApproximateNow(), sent_packet_manager_.GetRttStats());
 }
 
 QuicTime QuicConnection::GetPathDegradingDeadline() const {
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index aa13e51..86da486 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2925,7 +2925,8 @@
   }
   connection_.ProcessUdpPacket(
       kSelfAddress, kPeerAddress,
-      QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+      QuicReceivedPacket(buffer, encrypted_length, clock_.ApproximateNow(),
+                         false));
 
   EXPECT_EQ(kMaxOutgoingPacketSize, connection_.max_packet_length());
 }
@@ -2972,7 +2973,8 @@
   }
   connection_.ProcessUdpPacket(
       kSelfAddress, kPeerAddress,
-      QuicReceivedPacket(buffer, encrypted_length, QuicTime::Zero(), false));
+      QuicReceivedPacket(buffer, encrypted_length, clock_.ApproximateNow(),
+                         false));
 
   // Here, the limit imposed by the writer is lower than the size of the packet
   // received, so the writer max packet size is used.
@@ -11551,7 +11553,10 @@
   // SetFromConfig is always called after construction from InitializeSession.
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
-  EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber());
+  EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() {
+    connection_.RemoveEncrypter(ENCRYPTION_INITIAL);
+    connection_.NeuterUnencryptedPackets();
+  }));
   QuicConfig config;
   connection_.SetFromConfig(config);
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
@@ -11576,13 +11581,29 @@
                            std::make_unique<TaggingEncrypter>(0x01));
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE);
   // Verify HANDSHAKE packet gets processed.
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
+  } else {
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+  }
   connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
-  ASSERT_TRUE(connection_.HasPendingAcks());
-  // Send ACKs.
-  clock_.AdvanceTime(connection_.GetAckAlarm()->deadline() - clock_.Now());
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
-  connection_.GetAckAlarm()->Fire();
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    // Verify immediate ACK has been sent out when flush went out of scope.
+    ASSERT_FALSE(connection_.HasPendingAcks());
+  } else {
+    ASSERT_TRUE(connection_.HasPendingAcks());
+    // Send ACKs.
+    clock_.AdvanceTime(connection_.GetAckAlarm()->deadline() - clock_.Now());
+    connection_.GetAckAlarm()->Fire();
+  }
   ASSERT_FALSE(writer_->ack_frames().empty());
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    // Verify the ack_delay_time in the sent HANDSHAKE ACK frame is 100ms.
+    EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100),
+              writer_->ack_frames()[0].ack_delay_time);
+    ASSERT_TRUE(writer_->coalesced_packet() == nullptr);
+    return;
+  }
   // Verify the ack_delay_time in the INITIAL ACK frame is 1ms.
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1),
             writer_->ack_frames()[0].ack_delay_time);
@@ -15535,6 +15556,73 @@
   EXPECT_TRUE(connection_.connected());
 }
 
+TEST_P(QuicConnectionTest, ReportedAckDelayIncludesQueuingDelay) {
+  if (!version().HasIetfQuicFrames()) {
+    return;
+  }
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  QuicConfig config;
+  config.set_max_undecryptable_packets(3);
+  connection_.SetFromConfig(config);
+
+  // Receive 1-RTT ack-eliciting packet while keys are not available.
+  connection_.RemoveDecrypter(ENCRYPTION_FORWARD_SECURE);
+  peer_framer_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+                            std::make_unique<TaggingEncrypter>(0x01));
+  QuicFrames frames;
+  frames.push_back(QuicFrame(QuicPingFrame()));
+  frames.push_back(QuicFrame(QuicPaddingFrame(100)));
+  QuicPacketHeader header =
+      ConstructPacketHeader(30, ENCRYPTION_FORWARD_SECURE);
+  std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames));
+
+  char buffer[kMaxOutgoingPacketSize];
+  size_t encrypted_length = peer_framer_.EncryptPayload(
+      ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(30), *packet, buffer,
+      kMaxOutgoingPacketSize);
+  EXPECT_EQ(0u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+  const QuicTime packet_receipt_time = clock_.Now();
+  connection_.ProcessUdpPacket(
+      kSelfAddress, kPeerAddress,
+      QuicReceivedPacket(buffer, encrypted_length, clock_.Now(), false));
+  if (connection_.GetSendAlarm()->IsSet()) {
+    connection_.GetSendAlarm()->Fire();
+  }
+  ASSERT_EQ(1u, QuicConnectionPeer::NumUndecryptablePackets(&connection_));
+  // 1-RTT keys become available after 10ms.
+  const QuicTime::Delta kQueuingDelay = QuicTime::Delta::FromMilliseconds(10);
+  clock_.AdvanceTime(kQueuingDelay);
+  EXPECT_FALSE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  SetDecrypter(ENCRYPTION_FORWARD_SECURE,
+               std::make_unique<StrictTaggingDecrypter>(0x01));
+  ASSERT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet());
+
+  connection_.GetProcessUndecryptablePacketsAlarm()->Fire();
+  ASSERT_TRUE(connection_.HasPendingAcks());
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    EXPECT_EQ(packet_receipt_time + DefaultDelayedAckTime(),
+              connection_.GetAckAlarm()->deadline());
+    clock_.AdvanceTime(packet_receipt_time + DefaultDelayedAckTime() -
+                       clock_.Now());
+  } else {
+    EXPECT_EQ(clock_.Now() + DefaultDelayedAckTime(),
+              connection_.GetAckAlarm()->deadline());
+    clock_.AdvanceTime(DefaultDelayedAckTime());
+  }
+  // Fire ACK alarm.
+  connection_.GetAckAlarm()->Fire();
+  ASSERT_EQ(1u, writer_->ack_frames().size());
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    // Verify ACK delay time does not include queuing delay.
+    EXPECT_EQ(DefaultDelayedAckTime(), writer_->ack_frames()[0].ack_delay_time);
+  } else {
+    // Verify ACK delay time = queuing delay + ack delay
+    EXPECT_EQ(DefaultDelayedAckTime() + kQueuingDelay,
+              writer_->ack_frames()[0].ack_delay_time);
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 106288e..90def64 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -91,6 +91,8 @@
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_conservative_bursts, false)
 // If true, stop resetting ideal_next_packet_send_time_ in pacing sender.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_donot_reset_ideal_next_packet_send_time, false)
+// If true, update ACK timeout based on packet receipt time rather than now.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_update_ack_timeout_on_receipt_time, true)
 // If true, use BBRv2 as the default congestion controller. Takes precedence over --quic_default_to_bbr.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_default_to_bbr_v2, false)
 // If true, use new connection ID in connection migration.
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index d0f1578..c4e7333 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -234,7 +234,7 @@
 void QuicReceivedPacketManager::MaybeUpdateAckTimeout(
     bool should_last_packet_instigate_acks,
     QuicPacketNumber last_received_packet_number,
-    QuicTime now,
+    QuicTime last_packet_receipt_time, QuicTime now,
     const RttStats* rtt_stats) {
   if (!ack_frame_updated_) {
     // ACK frame has not been updated, nothing to do.
@@ -268,8 +268,24 @@
     return;
   }
 
+  QuicTime ack_timeout_base = now;
+  const bool quic_update_ack_timeout_on_receipt_time =
+      GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time);
+  if (quic_update_ack_timeout_on_receipt_time) {
+    if (last_packet_receipt_time <= now) {
+      QUIC_CODE_COUNT(quic_update_ack_timeout_on_receipt_time);
+      ack_timeout_base = last_packet_receipt_time;
+    } else {
+      QUIC_CODE_COUNT(quic_update_ack_timeout_on_now);
+      ack_timeout_base = now;
+    }
+  }
   QuicTime updated_ack_time =
-      now + GetMaxAckDelay(last_received_packet_number, *rtt_stats);
+      ack_timeout_base +
+      GetMaxAckDelay(last_received_packet_number, *rtt_stats);
+  if (quic_update_ack_timeout_on_receipt_time) {
+    updated_ack_time = std::max(now, updated_ack_time);
+  }
   if (!ack_timeout_.IsInitialized() || ack_timeout_ > updated_ack_time) {
     ack_timeout_ = updated_ack_time;
   }
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h
index 21f7f04..7d8edf8 100644
--- a/quic/core/quic_received_packet_manager.h
+++ b/quic/core/quic_received_packet_manager.h
@@ -64,7 +64,7 @@
   // Otherwise, ACK needs to be sent by the specified time.
   void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks,
                              QuicPacketNumber last_received_packet_number,
-                             QuicTime now,
+                             QuicTime last_packet_receipt_time, QuicTime now,
                              const RttStats* rtt_stats);
 
   // Resets ACK related states, called after an ACK is successfully sent.
diff --git a/quic/core/quic_received_packet_manager_test.cc b/quic/core/quic_received_packet_manager_test.cc
index cc04381..0bb6160 100644
--- a/quic/core/quic_received_packet_manager_test.cc
+++ b/quic/core/quic_received_packet_manager_test.cc
@@ -67,8 +67,9 @@
                              uint64_t last_received_packet_number) {
     received_manager_.MaybeUpdateAckTimeout(
         should_last_packet_instigate_acks,
-        QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
-        &rtt_stats_);
+        QuicPacketNumber(last_received_packet_number),
+        /*last_packet_receipt_time=*/clock_.ApproximateNow(),
+        /*now=*/clock_.ApproximateNow(), &rtt_stats_);
   }
 
   void CheckAckTimeout(QuicTime time) {
@@ -637,6 +638,54 @@
   }
 }
 
+TEST_F(QuicReceivedPacketManagerTest, UpdateAckTimeoutOnPacketReceiptTime) {
+  EXPECT_FALSE(HasPendingAck());
+
+  // Received packets 3 and 4.
+  QuicTime packet_receipt_time3 = clock_.ApproximateNow();
+  // Packet 3 gets processed after 10ms.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+  RecordPacketReceipt(3, packet_receipt_time3);
+  received_manager_.MaybeUpdateAckTimeout(
+      kInstigateAck, QuicPacketNumber(3),
+      /*last_packet_receipt_time=*/packet_receipt_time3,
+      clock_.ApproximateNow(), &rtt_stats_);
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    // Make sure ACK timeout is based on receipt time.
+    CheckAckTimeout(packet_receipt_time3 + kDelayedAckTime);
+  } else {
+    // Make sure ACK timeout is based on now.
+    CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+  }
+
+  RecordPacketReceipt(4, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 4);
+  // Immediate ack is sent.
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_F(QuicReceivedPacketManagerTest,
+       UpdateAckTimeoutOnPacketReceiptTimeLongerQueuingTime) {
+  EXPECT_FALSE(HasPendingAck());
+
+  // Received packets 3 and 4.
+  QuicTime packet_receipt_time3 = clock_.ApproximateNow();
+  // Packet 3 gets processed after 100ms.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
+  RecordPacketReceipt(3, packet_receipt_time3);
+  received_manager_.MaybeUpdateAckTimeout(
+      kInstigateAck, QuicPacketNumber(3),
+      /*last_packet_receipt_time=*/packet_receipt_time3,
+      clock_.ApproximateNow(), &rtt_stats_);
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    // Given 100ms > ack delay, verify immediate ACK.
+    CheckAckTimeout(clock_.ApproximateNow());
+  } else {
+    // Make sure ACK timeout is based on now.
+    CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/uber_received_packet_manager.cc b/quic/core/uber_received_packet_manager.cc
index c25329c..62411d5 100644
--- a/quic/core/uber_received_packet_manager.cc
+++ b/quic/core/uber_received_packet_manager.cc
@@ -76,18 +76,19 @@
     bool should_last_packet_instigate_acks,
     EncryptionLevel decrypted_packet_level,
     QuicPacketNumber last_received_packet_number,
-    QuicTime now,
+    QuicTime last_packet_receipt_time, QuicTime now,
     const RttStats* rtt_stats) {
   if (!supports_multiple_packet_number_spaces_) {
     received_packet_managers_[0].MaybeUpdateAckTimeout(
-        should_last_packet_instigate_acks, last_received_packet_number, now,
-        rtt_stats);
+        should_last_packet_instigate_acks, last_received_packet_number,
+        last_packet_receipt_time, now, rtt_stats);
     return;
   }
   received_packet_managers_[QuicUtils::GetPacketNumberSpace(
                                 decrypted_packet_level)]
       .MaybeUpdateAckTimeout(should_last_packet_instigate_acks,
-                             last_received_packet_number, now, rtt_stats);
+                             last_received_packet_number,
+                             last_packet_receipt_time, now, rtt_stats);
 }
 
 void UberReceivedPacketManager::ResetAckStates(
diff --git a/quic/core/uber_received_packet_manager.h b/quic/core/uber_received_packet_manager.h
index 3dddbda..c0c3e69 100644
--- a/quic/core/uber_received_packet_manager.h
+++ b/quic/core/uber_received_packet_manager.h
@@ -47,7 +47,7 @@
   void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks,
                              EncryptionLevel decrypted_packet_level,
                              QuicPacketNumber last_received_packet_number,
-                             QuicTime now,
+                             QuicTime last_packet_receipt_time, QuicTime now,
                              const RttStats* rtt_stats);
 
   // Resets ACK related states, called after an ACK is successfully sent.
diff --git a/quic/core/uber_received_packet_manager_test.cc b/quic/core/uber_received_packet_manager_test.cc
index 77731fb..8ca3ae9 100644
--- a/quic/core/uber_received_packet_manager_test.cc
+++ b/quic/core/uber_received_packet_manager_test.cc
@@ -85,7 +85,7 @@
     manager_->MaybeUpdateAckTimeout(
         should_last_packet_instigate_acks, decrypted_packet_level,
         QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(),
-        &rtt_stats_);
+        clock_.ApproximateNow(), &rtt_stats_);
   }
 
   void CheckAckTimeout(QuicTime time) {
@@ -522,6 +522,40 @@
   EXPECT_FALSE(HasPendingAck());
 }
 
+TEST_F(UberReceivedPacketManagerTest,
+       AckTimeoutForPreviouslyUndecryptablePackets) {
+  manager_->EnableMultiplePacketNumberSpacesSupport(Perspective::IS_SERVER);
+  EXPECT_FALSE(HasPendingAck());
+  EXPECT_FALSE(manager_->IsAckFrameUpdated());
+
+  // Received undecryptable 1-RTT packet 4.
+  const QuicTime packet_receipt_time4 = clock_.ApproximateNow();
+  // 1-RTT keys become available after 10ms because HANDSHAKE 5 gets received.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+  RecordPacketReceipt(ENCRYPTION_HANDSHAKE, 5);
+  MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_HANDSHAKE, 5);
+  EXPECT_TRUE(HasPendingAck());
+  RecordPacketReceipt(ENCRYPTION_FORWARD_SECURE, 4);
+  manager_->MaybeUpdateAckTimeout(kInstigateAck, ENCRYPTION_FORWARD_SECURE,
+                                  QuicPacketNumber(4), packet_receipt_time4,
+                                  clock_.ApproximateNow(), &rtt_stats_);
+
+  // Send delayed handshake ACK.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  EXPECT_TRUE(HasPendingAck());
+  if (GetQuicReloadableFlag(quic_update_ack_timeout_on_receipt_time)) {
+    // Verify ACK delay is based on packet receipt time.
+    CheckAckTimeout(clock_.ApproximateNow() -
+                    QuicTime::Delta::FromMilliseconds(11) + kDelayedAckTime);
+  } else {
+    // Delayed ack is scheduled.
+    CheckAckTimeout(clock_.ApproximateNow() -
+                    QuicTime::Delta::FromMilliseconds(1) + kDelayedAckTime);
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic