Landing Recent QUIC changes until 11:30 AM, Aug 11, 2018 UTC-4

Update QUIC flag values.


Bundle BbrSender and its BandwidthSampler in memory, hopefully reduces cache misses. Not protected.

Merge internal change: 208339929

https://chromium-review.googlesource.com/c/1173696/


Move the delegate from PacketTransportInterface to QuartcPacketTransport.

This is the first step of getting rid of the three separate interfaces for
QuartcPacketWriter, QuartcPacketTransport, and PacketWriterInterface.

Threading requirements, debug info (packet number), and the fact that Quartc
owns and manages the entire ICE transport make this somewhat unwieldy at the
moment.  However, it should get better going forward.

This change makes quic::QuartcPacketTransport an interface for network I/O.
- Write() sends packets to the network
- Delegate::OnTransportCanWrite() indicates that writes are unblocked
- Delegate::OnTransportReceived() passes incoming packets to QUIC

PacketTransportInterface adds on the signaling and config required for ICE.
- Connect() allows the caller to specify initial parameters and start ICE
- Disconnect() allows the caller to shut down the ICE transport
- SetDeliveryMode() and SetIpPrivacyPolicy() modify ICE parameters at runtime
- OnTransportMessageReceived() and OutgoingTransportMessages() provide a
channel for signaling ICE candidates

Going forward, Quartc will share an ICE transport with other components and will
not need to manage the signaling aspects of ICE.  PacketTransportInterface can
go away once that happens.

QuartcPacketWriter remains an implementation of QuicPacketWriter.  It handles
network output through the wrapped QuartcPacketTransport.  It adds two pieces of
functionality on top of QuicPacketWriter: it adds packet numbers to every
outgoing packet and allows the caller to set the packet transport's delegate.

Once QuicPacketWriter::WritePacket() includes packet numbers in its interface,
it will also be possible to merge QuartcPacketWriter and QuartcPacketTransport
into a single network I/O interface for quic/quartc.

Finally, QUIC expects the QuartcPacketTransport::Delegate calls to be serialized
with other QUIC operations.  The way that Quartc does this serialization today
becomes slightly more complex.  Since QUIC now calls SetDelegate(), Quartc needs
a wrapper to intercept the Delegate and perform the thread hop to the QUIC
executor.  This is necessary pain induced by thread-hopping.

The thread-safe wrapper will become thinner when PacketTransportInterface is
deleted.  It will go away entirely when we replace quartc_thread_safe with a
better synchronization mechanism.

FIG_CHANGESET=c4301c7fdf0e83b365a939cc233dc7b006f55884

Merge internal change: 208285103

https://chromium-review.googlesource.com/c/1173695/


In QUIC, when session decides what to write, let IsPacketUsefulForRetransmittableData drops packets earlier. Protected by FLAGS_quic_reloadable_flag_quic_fix_is_useful_for_retrans.

Merge internal change: 207934023

https://chromium-review.googlesource.com/c/1173333/


Make QuicSession::GetStream slightly faster by skipping the lookup into the static stream map, when possible. Protected by FLAGS_quic_reloadable_flag_quic_session_faster_get_stream.

Merge internal change: 207921542

https://chromium-review.googlesource.com/c/1173332/


In QUIC, if a newer WINDOW_UPDATE frame gets acked, consider all older WINDOW_UPDATE gets acked. Protected by FLAGS_quic_reloadable_flag_quic_donot_retransmit_old_window_update2.

Merge internal change: 207915791

https://chromium-review.googlesource.com/c/1173331/


In QUIC, only process stateless resets on the client side. Protected by FLAGS_quic_reloadable_flag_quic_process_stateless_reset_at_client_only.

When the flag is on, server won't bother to read |header->possible_stateless_reset_token|, thus saving a small amount of cpu. This is a micro optimization. No externally visible behavior change.

Merge internal change: 207883948

https://chromium-review.googlesource.com/c/1172928/


In QUIC, try to aggregate acked stream frame. Protected by FLAGS_quic_reloadable_flag_quic_aggregate_acked_stream_frames.

Merge internal change: 207746798

https://chromium-review.googlesource.com/c/1172927/


Improve Quartc's responsiveness to changes in congestion control parameters.

Issue a callback from QUIC to Quartc whenever congestion control changes.  This
callback reports three parameters:  bandwidth estimate, pacing rate, and latest
RTT.  The callback fires whenever QuicSendPacketManager calls
OnCongestionChange().  This happens after every ack frame with an rtt update,
acked packets, or lost packets.

Reporting changes in congestion control parameters to Quartc immediately, rather
than waiting up to 200 ms for Quartc to scrape them from stats, should improve
responsiveness to congestion control changes, especially on low-RTT networks
where changes can happen on timescales much shorter than 200 ms.

Quartc now uses the minimum of BWE and pacing rate for rate controls in the
Brain.  This should avoid building long client-side buffers during PROBE_RTT,
DRAIN, or low-gain PROBE_BW phases.  During these phases, the BWE is higher than
the pacing rate.  If Quartc continues to produce data at the BWE, it will
overproduce and buffer data.

Since low-gain phases tend to last on the order of 1 RTT, it does not make sense
to adapt to the pacing rate without also getting a callback as soon as it
changes.  Scraping every 200 ms may easily miss gain transitions (either
obtaining a higher pacing rate just before the low-gain phase starts or
obtaining a lower pacing rate just before the low-gain phase ends).

FIG_CHANGESET=37546b8b8e52bdc4af9a28f394f1387db4bb597f

Merge internal change: 207729769

https://chromium-review.googlesource.com/c/1172926/


Refactor quic::PerPacketOptions

Turn it from a class into a struct (since it only exists to carry a bunch of
values around).  Also make Clone() return unique_ptr.

Merge internal change: 207625151

https://chromium-review.googlesource.com/c/1172923/


Remove a bogus DCHECK from QuicStream::SetPriority which would be triggered if a server received a PRIORITY frame after having sent any of the response body.

Merge internal change: 207619365

https://chromium-review.googlesource.com/c/1172922/


Reorder an OR statement in IsPacketUsefulForRetransmittableData() to avoid calling HasRetransmittableFrames() when it's not necessary.  No functional change, not flag protected.

Merge internal change: 207585541

https://chromium-review.googlesource.com/c/1172921/

R=rch@chromium.org

Change-Id: I144c4346e80b418ddf8a70b60642e9716e902cf7
Reviewed-on: https://chromium-review.googlesource.com/1173701
Commit-Queue: Bin Wu <wub@chromium.org>
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: Ryan Hamilton <rch@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#582822}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 076a1edc410d52aa6794f6146e1baa9d6d3fc090
diff --git a/quic/quic_flags_list.h b/quic/quic_flags_list.h
index ce03b59..7a3c93e 100644
--- a/quic/quic_flags_list.h
+++ b/quic/quic_flags_list.h
@@ -149,7 +149,7 @@
 
 // When you\'re app-limited entering recovery, stay app-limited until you exit
 // recovery in QUIC BBR.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_app_limited_recovery, true)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_app_limited_recovery, false)
 
 // If true, mark QUIC as app-limited after sending queued packets or
 // retransmisssions and we then become congestion control blocked.
@@ -191,3 +191,32 @@
 // If true, QuicCryptoServerConfig::EvaluateClientHello will use GetCertChain
 // instead of the more expensive GetProof.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_get_cert_chain, false)
+
+// If true, try to aggregate acked stream frames.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_aggregate_acked_stream_frames,
+          false)
+
+// If true, only process stateless reset packets on the client side.
+QUIC_FLAG(
+    bool,
+    FLAGS_quic_reloadable_flag_quic_process_stateless_reset_at_client_only,
+    false)
+
+// If true, do not retransmit old window update frames.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_donot_retransmit_old_window_update2,
+          false)
+
+// If ture, make QuicSession::GetStream faster by skipping the lookup into
+// static stream map, when possible.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_session_faster_get_stream,
+          false)
+
+// If true, when session decides what to write, set a approximate retransmission
+// for packets to be retransmitted. Also check packet state in
+// IsPacketUsefulForRetransmittableData.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_fix_is_useful_for_retrans,
+          false)
diff --git a/third_party/quic/core/congestion_control/bbr_sender.cc b/third_party/quic/core/congestion_control/bbr_sender.cc
index 90e5db9..1b18fc7 100644
--- a/third_party/quic/core/congestion_control/bbr_sender.cc
+++ b/third_party/quic/core/congestion_control/bbr_sender.cc
@@ -81,12 +81,13 @@
                      const QuicUnackedPacketMap* unacked_packets,
                      QuicPacketCount initial_tcp_congestion_window,
                      QuicPacketCount max_tcp_congestion_window,
-                     QuicRandom* random)
+                     QuicRandom* random,
+                     BandwidthSamplerInterface* sampler)
     : rtt_stats_(rtt_stats),
       unacked_packets_(unacked_packets),
       random_(random),
       mode_(STARTUP),
-      sampler_(new BandwidthSampler()),
+      sampler_(sampler),
       round_trip_count_(0),
       last_sent_packet_(0),
       current_round_trip_end_(0),
diff --git a/third_party/quic/core/congestion_control/bbr_sender.h b/third_party/quic/core/congestion_control/bbr_sender.h
index f91ad14..1411eb6 100644
--- a/third_party/quic/core/congestion_control/bbr_sender.h
+++ b/third_party/quic/core/congestion_control/bbr_sender.h
@@ -91,13 +91,32 @@
     QuicPacketNumber end_of_app_limited_phase;
   };
 
-  BbrSender(const RttStats* rtt_stats,
-            const QuicUnackedPacketMap* unacked_packets,
-            QuicPacketCount initial_tcp_congestion_window,
-            QuicPacketCount max_tcp_congestion_window,
-            QuicRandom* random);
-  BbrSender(const BbrSender&) = delete;
-  BbrSender& operator=(const BbrSender&) = delete;
+  template <typename BandwidthSamplerT = BandwidthSampler>
+  static BbrSender* Create(const RttStats* rtt_stats,
+                           const QuicUnackedPacketMap* unacked_packets,
+                           QuicPacketCount initial_tcp_congestion_window,
+                           QuicPacketCount max_tcp_congestion_window,
+                           QuicRandom* random) {
+    struct SenderSamplerBundle : public BbrSender {
+      SenderSamplerBundle(const RttStats* rtt_stats,
+                          const QuicUnackedPacketMap* unacked_packets,
+                          QuicPacketCount initial_tcp_congestion_window,
+                          QuicPacketCount max_tcp_congestion_window,
+                          QuicRandom* random)
+          : BbrSender(rtt_stats,
+                      unacked_packets,
+                      initial_tcp_congestion_window,
+                      max_tcp_congestion_window,
+                      random,
+                      &sampler) {}
+      BandwidthSamplerT sampler;
+    };
+
+    return new SenderSamplerBundle(rtt_stats, unacked_packets,
+                                   initial_tcp_congestion_window,
+                                   max_tcp_congestion_window, random);
+  }
+
   ~BbrSender() override;
 
   // Start implementation of SendAlgorithmInterface.
@@ -167,6 +186,16 @@
 
   DebugState ExportDebugState() const;
 
+ protected:
+  BbrSender(const RttStats* rtt_stats,
+            const QuicUnackedPacketMap* unacked_packets,
+            QuicPacketCount initial_tcp_congestion_window,
+            QuicPacketCount max_tcp_congestion_window,
+            QuicRandom* random,
+            BandwidthSamplerInterface* sampler);
+  BbrSender(const BbrSender&) = delete;
+  BbrSender& operator=(const BbrSender&) = delete;
+
  private:
   typedef WindowedFilter<QuicBandwidth,
                          MaxFilter<QuicBandwidth>,
@@ -252,7 +281,7 @@
 
   // Bandwidth sampler provides BBR with the bandwidth measurements at
   // individual points.
-  std::unique_ptr<BandwidthSamplerInterface> sampler_;
+  BandwidthSamplerInterface* sampler_;  // Not owned.
 
   // The number of the round trips that have occurred during the connection.
   QuicRoundTripCount round_trip_count_;
diff --git a/third_party/quic/core/congestion_control/bbr_sender_test.cc b/third_party/quic/core/congestion_control/bbr_sender_test.cc
index 600a9db..849378b 100644
--- a/third_party/quic/core/congestion_control/bbr_sender_test.cc
+++ b/third_party/quic/core/congestion_control/bbr_sender_test.cc
@@ -126,7 +126,7 @@
     const RttStats* rtt_stats =
         endpoint->connection()->sent_packet_manager().GetRttStats();
     // Ownership of the sender will be overtaken by the endpoint.
-    BbrSender* sender = new BbrSender(
+    BbrSender* sender = BbrSender::Create(
         rtt_stats,
         QuicSentPacketManagerPeer::GetUnackedPacketMap(
             QuicConnectionPeer::GetSentPacketManager(endpoint->connection())),
@@ -330,7 +330,7 @@
 TEST_F(BbrSenderTest, SimpleTransferAckDecimation) {
   // Decrease the CWND gain so extra CWND is required with stretch acks.
   FLAGS_quic_bbr_cwnd_gain = 1.0;
-  sender_ = new BbrSender(
+  sender_ = BbrSender::Create(
       rtt_stats_,
       QuicSentPacketManagerPeer::GetUnackedPacketMap(
           QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection())),
diff --git a/third_party/quic/core/congestion_control/send_algorithm_interface.cc b/third_party/quic/core/congestion_control/send_algorithm_interface.cc
index 5e4b471..a202710 100644
--- a/third_party/quic/core/congestion_control/send_algorithm_interface.cc
+++ b/third_party/quic/core/congestion_control/send_algorithm_interface.cc
@@ -29,9 +29,9 @@
   QuicPacketCount max_congestion_window = kDefaultMaxCongestionWindowPackets;
   switch (congestion_control_type) {
     case kBBR:
-      return new BbrSender(rtt_stats, unacked_packets,
-                           initial_congestion_window, max_congestion_window,
-                           random);
+      return BbrSender::Create(rtt_stats, unacked_packets,
+                               initial_congestion_window, max_congestion_window,
+                               random);
     case kPCC:
       if (GetQuicReloadableFlag(quic_enable_pcc3)) {
         return CreatePccSender(clock, rtt_stats, unacked_packets, random, stats,
diff --git a/third_party/quic/core/http/end_to_end_test.cc b/third_party/quic/core/http/end_to_end_test.cc
index de85732..030d12d 100644
--- a/third_party/quic/core/http/end_to_end_test.cc
+++ b/third_party/quic/core/http/end_to_end_test.cc
@@ -874,6 +874,37 @@
   VerifyCleanConnection(true);
 }
 
+// Regression test for b/80090281.
+TEST_P(EndToEndTest, LargePostWithPacketLossAndAlwaysBundleWindowUpdates) {
+  ASSERT_TRUE(Initialize());
+
+  // Wait for the server SHLO before upping the packet loss.
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+  server_thread_->WaitForCryptoHandshakeConfirmed();
+
+  // Normally server only bundles a retransmittable frame once every other
+  // kMaxConsecutiveNonRetransmittablePackets ack-only packets. Setting the max
+  // to 0 to reliably reproduce b/80090281.
+  server_thread_->Schedule([this]() {
+    QuicConnectionPeer::SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames(
+        GetServerConnection(), 0);
+  });
+
+  SetPacketLossPercentage(30);
+
+  // 10 KB body.
+  QuicString body(1024 * 10, 'a');
+  SpdyHeaderBlock headers;
+  headers[":method"] = "POST";
+  headers[":path"] = "/foo";
+  headers[":scheme"] = "https";
+  headers[":authority"] = server_hostname_;
+
+  EXPECT_EQ(kFooResponseBody,
+            client_->SendCustomSynchronousRequest(headers, body));
+  VerifyCleanConnection(true);
+}
+
 TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) {
   if (!BothSidesSupportStatelessRejects()) {
     // Connect with lower fake packet loss than we'd like to test.  Until
diff --git a/third_party/quic/core/http/quic_spdy_session.cc b/third_party/quic/core/http/quic_spdy_session.cc
index d600c51..da1fdbd 100644
--- a/third_party/quic/core/http/quic_spdy_session.cc
+++ b/third_party/quic/core/http/quic_spdy_session.cc
@@ -342,7 +342,7 @@
 
   headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this));
   DCHECK_EQ(kHeadersStreamId, headers_stream_->id());
-  static_streams()[kHeadersStreamId] = headers_stream_.get();
+  RegisterStaticStream(kHeadersStreamId, headers_stream_.get());
 
   set_max_uncompressed_header_bytes(max_inbound_header_list_size_);
 
diff --git a/third_party/quic/core/http/quic_spdy_stream_test.cc b/third_party/quic/core/http/quic_spdy_stream_test.cc
index 394a180..ad7c5f7 100644
--- a/third_party/quic/core/http/quic_spdy_stream_test.cc
+++ b/third_party/quic/core/http/quic_spdy_stream_test.cc
@@ -1047,6 +1047,16 @@
   EXPECT_EQ(kV3HighestPriority, stream_->priority());
 }
 
+TEST_P(QuicSpdyStreamTest, OnPriorityFrameAfterSendingData) {
+  Initialize(kShouldProcessData);
+
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _))
+      .WillOnce(Return(QuicConsumedData(4, true)));
+  stream_->WriteOrBufferData("data", true, nullptr);
+  stream_->OnPriorityFrame(kV3HighestPriority);
+  EXPECT_EQ(kV3HighestPriority, stream_->priority());
+}
+
 TEST_P(QuicSpdyStreamTest, SetPriorityBeforeUpdateStreamPriority) {
   MockQuicConnection* connection = new testing::StrictMock<MockQuicConnection>(
       &helper_, &alarm_factory_, Perspective::IS_SERVER,
diff --git a/third_party/quic/core/quic_connection.cc b/third_party/quic/core/quic_connection.cc
index 25a2fe4..43e7ef4 100644
--- a/third_party/quic/core/quic_connection.cc
+++ b/third_party/quic/core/quic_connection.cc
@@ -313,6 +313,8 @@
       write_error_occurred_(false),
       no_stop_waiting_frames_(transport_version() > QUIC_VERSION_43),
       consecutive_num_packets_with_no_retransmittable_frames_(0),
+      max_consecutive_num_packets_with_no_retransmittable_frames_(
+          kMaxConsecutiveNonRetransmittablePackets),
       fill_up_link_during_probing_(false),
       probing_retransmission_pending_(false),
       stateless_reset_token_received_(false),
@@ -326,7 +328,8 @@
           GetQuicReloadableFlag(quic_add_to_blocked_list_if_writer_blocked)),
       ack_reordered_packets_(GetQuicReloadableFlag(quic_ack_reordered_packets)),
       retransmissions_app_limited_(
-          GetQuicReloadableFlag(quic_retransmissions_app_limited)) {
+          GetQuicReloadableFlag(quic_retransmissions_app_limited)),
+      donot_retransmit_old_window_updates_(false) {
   if (ack_mode_ == ACK_DECIMATION) {
     QUIC_FLAG_COUNT(quic_reloadable_flag_quic_enable_ack_decimation);
   }
@@ -2072,14 +2075,14 @@
   QuicTime packet_send_time = clock_->Now();
   if (supports_release_time_ && per_packet_options_ != nullptr) {
     QuicTime next_release_time = sent_packet_manager_.GetNextReleaseTime();
-    uint64_t release_time_delay_ns = 0;
+    QuicTime::Delta release_time_delay = QuicTime::Delta::Zero();
     QuicTime now = packet_send_time;
     if (next_release_time > now) {
-      release_time_delay_ns = (next_release_time - now).ToMicroseconds() * 1000;
+      release_time_delay = next_release_time - now;
       // Set packet_send_time to the future to make the RTT estimation accurate.
       packet_send_time = next_release_time;
     }
-    per_packet_options_->SetReleaseTimeDelay(release_time_delay_ns);
+    per_packet_options_->release_time_delay = release_time_delay;
   }
   WriteResult result = writer_->WritePacket(
       packet->encrypted_buffer, encrypted_length, self_address().host(),
@@ -2351,11 +2354,13 @@
 
   packet_generator_.SetShouldSendAck(!no_stop_waiting_frames_);
   if (consecutive_num_packets_with_no_retransmittable_frames_ <
-      kMaxConsecutiveNonRetransmittablePackets) {
+      max_consecutive_num_packets_with_no_retransmittable_frames_) {
     return;
   }
   consecutive_num_packets_with_no_retransmittable_frames_ = 0;
-  if (packet_generator_.HasRetransmittableFrames()) {
+  if (packet_generator_.HasRetransmittableFrames() ||
+      (donot_retransmit_old_window_updates_ &&
+       visitor_->WillingAndAbleToWrite())) {
     // There are pending retransmittable frames.
     return;
   }
diff --git a/third_party/quic/core/quic_connection.h b/third_party/quic/core/quic_connection.h
index a0d370b..01d3966 100644
--- a/third_party/quic/core/quic_connection.h
+++ b/third_party/quic/core/quic_connection.h
@@ -146,9 +146,9 @@
   virtual void PostProcessAfterData() = 0;
 
   // Called when the connection sends ack after
-  // kMaxConsecutiveNonRetransmittablePackets consecutive not retransmittable
-  // packets sent. To instigate an ack from peer, a retransmittable frame needs
-  // to be added.
+  // max_consecutive_num_packets_with_no_retransmittable_frames_ consecutive not
+  // retransmittable packets sent. To instigate an ack from peer, a
+  // retransmittable frame needs to be added.
   virtual void OnAckNeedsRetransmittableFrame() = 0;
 
   // Called when a ping needs to be sent.
@@ -770,6 +770,12 @@
 
   bool IsPathDegrading() const { return is_path_degrading_; }
 
+  // TODO(wub): Remove this function once
+  // quic_reloadable_flag_quic_donot_retransmit_old_window_update is deprecated.
+  void set_donot_retransmit_old_window_updates(bool value) {
+    donot_retransmit_old_window_updates_ = value;
+  }
+
  protected:
   // Calls cancel() on all the alarms owned by this connection.
   void CancelAllAlarms();
@@ -1254,6 +1260,10 @@
 
   // Consecutive number of sent packets which have no retransmittable frames.
   size_t consecutive_num_packets_with_no_retransmittable_frames_;
+  // After this many packets sent without retransmittable frames, an artificial
+  // retransmittable frame(a WINDOW_UPDATE) will be created to solicit an ack
+  // from the peer. Default to kMaxConsecutiveNonRetransmittablePackets.
+  size_t max_consecutive_num_packets_with_no_retransmittable_frames_;
 
   // If true, the connection will fill up the pipe with extra data whenever the
   // congestion controller needs it in order to make a bandwidth estimate.  This
@@ -1297,6 +1307,10 @@
 
   // Latched value of quic_reloadable_flag_quic_retransmissions_app_limited.
   const bool retransmissions_app_limited_;
+
+  // Latched value of
+  // quic_reloadable_flag_quic_donot_retransmit_old_window_update.
+  bool donot_retransmit_old_window_updates_;
 };
 
 }  // namespace quic
diff --git a/third_party/quic/core/quic_control_frame_manager.cc b/third_party/quic/core/quic_control_frame_manager.cc
index 8d15ba3..db954a2 100644
--- a/third_party/quic/core/quic_control_frame_manager.cc
+++ b/third_party/quic/core/quic_control_frame_manager.cc
@@ -7,6 +7,7 @@
 #include "net/third_party/quic/core/quic_constants.h"
 #include "net/third_party/quic/core/quic_session.h"
 #include "net/third_party/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quic/platform/api/quic_map_util.h"
 #include "net/third_party/quic/platform/api/quic_string.h"
 
@@ -16,7 +17,9 @@
     : last_control_frame_id_(kInvalidControlFrameId),
       least_unacked_(1),
       least_unsent_(1),
-      session_(session) {}
+      session_(session),
+      donot_retransmit_old_window_updates_(
+          GetQuicReloadableFlag(quic_donot_retransmit_old_window_update2)) {}
 
 QuicControlFrameManager::~QuicControlFrameManager() {
   while (!control_frames_.empty()) {
@@ -97,6 +100,18 @@
         << "Send or retransmit a control frame with invalid control frame id";
     return;
   }
+  if (donot_retransmit_old_window_updates_ &&
+      frame.type == WINDOW_UPDATE_FRAME) {
+    QuicStreamId stream_id = frame.window_update_frame->stream_id;
+    if (QuicContainsKey(window_update_frames_, stream_id) &&
+        id > window_update_frames_[stream_id]) {
+      // Consider the older window update of the same stream as acked.
+      QUIC_FLAG_COUNT(
+          quic_reloadable_flag_quic_donot_retransmit_old_window_update2);
+      OnControlFrameIdAcked(window_update_frames_[stream_id]);
+    }
+    window_update_frames_[stream_id] = id;
+  }
   if (QuicContainsKey(pending_retransmissions_, id)) {
     // This is retransmitted control frame.
     pending_retransmissions_.erase(id);
@@ -116,36 +131,16 @@
 
 bool QuicControlFrameManager::OnControlFrameAcked(const QuicFrame& frame) {
   QuicControlFrameId id = GetControlFrameId(frame);
-  if (id == kInvalidControlFrameId) {
-    // Frame does not have a valid control frame ID, ignore it.
+  if (!OnControlFrameIdAcked(id)) {
     return false;
   }
-  if (id >= least_unsent_) {
-    QUIC_BUG << "Try to ack unsent control frame";
-    session_->connection()->CloseConnection(
-        QUIC_INTERNAL_ERROR, "Try to ack unsent control frame",
-        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-    RecordInternalErrorLocation(QUIC_CONTROL_FRAME_MANAGER_CONTROL_FRAME_ACKED);
-    return false;
-  }
-  if (id < least_unacked_ ||
-      GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
-          kInvalidControlFrameId) {
-    // This frame has already been acked.
-    return false;
-  }
-
-  // Set control frame ID of acked frames to 0.
-  SetControlFrameId(kInvalidControlFrameId,
-                    &control_frames_.at(id - least_unacked_));
-  // Remove acked control frames from pending retransmissions.
-  pending_retransmissions_.erase(id);
-  // Clean up control frames queue and increment least_unacked_.
-  while (!control_frames_.empty() &&
-         GetControlFrameId(control_frames_.front()) == kInvalidControlFrameId) {
-    DeleteFrame(&control_frames_.front());
-    control_frames_.pop_front();
-    ++least_unacked_;
+  if (donot_retransmit_old_window_updates_ &&
+      frame.type == WINDOW_UPDATE_FRAME) {
+    QuicStreamId stream_id = frame.window_update_frame->stream_id;
+    if (QuicContainsKey(window_update_frames_, stream_id) &&
+        window_update_frames_[stream_id] == id) {
+      window_update_frames_.erase(stream_id);
+    }
   }
   return true;
 }
@@ -275,6 +270,40 @@
   }
 }
 
+bool QuicControlFrameManager::OnControlFrameIdAcked(QuicControlFrameId id) {
+  if (id == kInvalidControlFrameId) {
+    // Frame does not have a valid control frame ID, ignore it.
+    return false;
+  }
+  if (id >= least_unsent_) {
+    QUIC_BUG << "Try to ack unsent control frame";
+    session_->connection()->CloseConnection(
+        QUIC_INTERNAL_ERROR, "Try to ack unsent control frame",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return false;
+  }
+  if (id < least_unacked_ ||
+      GetControlFrameId(control_frames_.at(id - least_unacked_)) ==
+          kInvalidControlFrameId) {
+    // This frame has already been acked.
+    return false;
+  }
+
+  // Set control frame ID of acked frames to 0.
+  SetControlFrameId(kInvalidControlFrameId,
+                    &control_frames_.at(id - least_unacked_));
+  // Remove acked control frames from pending retransmissions.
+  pending_retransmissions_.erase(id);
+  // Clean up control frames queue and increment least_unacked_.
+  while (!control_frames_.empty() &&
+         GetControlFrameId(control_frames_.front()) == kInvalidControlFrameId) {
+    DeleteFrame(&control_frames_.front());
+    control_frames_.pop_front();
+    ++least_unacked_;
+  }
+  return true;
+}
+
 bool QuicControlFrameManager::HasBufferedFrames() const {
   return least_unsent_ < least_unacked_ + control_frames_.size();
 }
diff --git a/third_party/quic/core/quic_control_frame_manager.h b/third_party/quic/core/quic_control_frame_manager.h
index e5b89cb..e15383d 100644
--- a/third_party/quic/core/quic_control_frame_manager.h
+++ b/third_party/quic/core/quic_control_frame_manager.h
@@ -83,6 +83,12 @@
   // sent.
   bool WillingToWrite() const;
 
+  // TODO(wub): Remove this function once
+  // quic_reloadable_flag_quic_donot_retransmit_old_window_update is deprecated.
+  bool donot_retransmit_old_window_updates() const {
+    return donot_retransmit_old_window_updates_;
+  }
+
  private:
   friend class test::QuicControlFrameManagerPeer;
 
@@ -95,6 +101,10 @@
   // Writes pending retransmissions if any.
   void WritePendingRetransmission();
 
+  // Called when frame with |id| gets acked. Returns true if |id| gets acked for
+  // the first time, return false otherwise.
+  bool OnControlFrameIdAcked(QuicControlFrameId id);
+
   // Retrieves the next pending retransmission. This must only be called when
   // there are pending retransmissions.
   QuicFrame NextPendingRetransmission() const;
@@ -121,6 +131,13 @@
 
   // Pointer to the owning QuicSession object.
   QuicSession* session_;
+
+  // Last sent window update frame for each stream.
+  QuicSmallMap<QuicStreamId, QuicControlFrameId, 10> window_update_frames_;
+
+  // Latched value of
+  // FLAGS_quic_reloadable_flag_quic_donot_retransmit_old_window_update2.
+  const bool donot_retransmit_old_window_updates_;
 };
 
 }  // namespace quic
diff --git a/third_party/quic/core/quic_control_frame_manager_test.cc b/third_party/quic/core/quic_control_frame_manager_test.cc
index 92be10c..23e1fb1 100644
--- a/third_party/quic/core/quic_control_frame_manager_test.cc
+++ b/third_party/quic/core/quic_control_frame_manager_test.cc
@@ -34,6 +34,10 @@
     DeleteFrame(&const_cast<QuicFrame&>(frame));
     return true;
   }
+  bool SaveControlFrame(const QuicFrame& frame) {
+    frame_ = frame;
+    return true;
+  }
 
  protected:
   void Initialize() {
@@ -74,6 +78,7 @@
   MockQuicConnection* connection_;
   std::unique_ptr<StrictMock<MockQuicSession>> session_;
   std::unique_ptr<QuicControlFrameManager> manager_;
+  QuicFrame frame_;
 };
 
 TEST_F(QuicControlFrameManagerTest, OnControlFrameAcked) {
@@ -206,6 +211,72 @@
   EXPECT_FALSE(manager_->WillingToWrite());
 }
 
+TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
+  SetQuicReloadableFlag(quic_donot_retransmit_old_window_update2, true);
+  Initialize();
+  // Send two more window updates of the same stream.
+  manager_->WriteOrBufferWindowUpdate(kTestStreamId, 200);
+  QuicWindowUpdateFrame window_update2(5, kTestStreamId, 200);
+
+  manager_->WriteOrBufferWindowUpdate(kTestStreamId, 300);
+  QuicWindowUpdateFrame window_update3(6, kTestStreamId, 300);
+  InSequence s;
+  // Flush all buffered control frames.
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .WillRepeatedly(
+          Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+  manager_->OnCanWrite();
+
+  // Mark all 3 window updates as lost.
+  manager_->OnControlFrameLost(QuicFrame(&window_update_));
+  manager_->OnControlFrameLost(QuicFrame(&window_update2));
+  manager_->OnControlFrameLost(QuicFrame(&window_update3));
+  EXPECT_TRUE(manager_->HasPendingRetransmission());
+  EXPECT_TRUE(manager_->WillingToWrite());
+
+  // Verify only the latest window update gets retransmitted.
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .WillOnce(Invoke(this, &QuicControlFrameManagerTest::SaveControlFrame));
+  manager_->OnCanWrite();
+  EXPECT_EQ(6u, frame_.window_update_frame->control_frame_id);
+  EXPECT_FALSE(manager_->HasPendingRetransmission());
+  EXPECT_FALSE(manager_->WillingToWrite());
+  DeleteFrame(&frame_);
+}
+
+TEST_F(QuicControlFrameManagerTest, RetransmitWindowUpdateOfDifferentStreams) {
+  SetQuicReloadableFlag(quic_donot_retransmit_old_window_update2, true);
+  Initialize();
+  // Send two more window updates of different streams.
+  manager_->WriteOrBufferWindowUpdate(kTestStreamId + 2, 200);
+  QuicWindowUpdateFrame window_update2(5, kTestStreamId + 2, 200);
+
+  manager_->WriteOrBufferWindowUpdate(kTestStreamId + 4, 300);
+  QuicWindowUpdateFrame window_update3(6, kTestStreamId + 4, 300);
+  InSequence s;
+  // Flush all buffered control frames.
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .WillRepeatedly(
+          Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+  manager_->OnCanWrite();
+
+  // Mark all 3 window updates as lost.
+  manager_->OnControlFrameLost(QuicFrame(&window_update_));
+  manager_->OnControlFrameLost(QuicFrame(&window_update2));
+  manager_->OnControlFrameLost(QuicFrame(&window_update3));
+  EXPECT_TRUE(manager_->HasPendingRetransmission());
+  EXPECT_TRUE(manager_->WillingToWrite());
+
+  // Verify all 3 window updates get retransmitted.
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .Times(3)
+      .WillRepeatedly(
+          Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
+  manager_->OnCanWrite();
+  EXPECT_FALSE(manager_->HasPendingRetransmission());
+  EXPECT_FALSE(manager_->WillingToWrite());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/third_party/quic/core/quic_framer.cc b/third_party/quic/core/quic_framer.cc
index 9c05cf5..14b7485 100644
--- a/third_party/quic/core/quic_framer.cc
+++ b/third_party/quic/core/quic_framer.cc
@@ -256,7 +256,9 @@
       alternative_decrypter_latch_(false),
       perspective_(perspective),
       validate_flags_(true),
-      data_producer_(nullptr) {
+      data_producer_(nullptr),
+      process_stateless_reset_at_client_only_(
+          GetQuicReloadableFlag(quic_process_stateless_reset_at_client_only)) {
   DCHECK(!supported_versions.empty());
   version_ = supported_versions_[0];
   decrypter_ = QuicMakeUnique<NullDecrypter>(perspective);
@@ -1182,15 +1184,37 @@
                                        const QuicEncryptedPacket& packet,
                                        char* decrypted_buffer,
                                        size_t buffer_length) {
+  DCHECK(!header->has_possible_stateless_reset_token);
   if (header->form == SHORT_HEADER) {
-    // Peak possible stateless reset token. Will only be used on decryption
-    // failure.
-    QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
-    if (remaining.length() >= sizeof(header->possible_stateless_reset_token)) {
-      remaining.copy(
-          reinterpret_cast<char*>(&header->possible_stateless_reset_token),
-          sizeof(header->possible_stateless_reset_token),
-          remaining.length() - sizeof(header->possible_stateless_reset_token));
+    if (!process_stateless_reset_at_client_only_) {
+      // Peak possible stateless reset token. Will only be used on decryption
+      // failure.
+      QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
+      if (remaining.length() >=
+          sizeof(header->possible_stateless_reset_token)) {
+        remaining.copy(
+            reinterpret_cast<char*>(&header->possible_stateless_reset_token),
+            sizeof(header->possible_stateless_reset_token),
+            remaining.length() -
+                sizeof(header->possible_stateless_reset_token));
+      }
+    } else {
+      QUIC_FLAG_COUNT(
+          quic_reloadable_flag_quic_process_stateless_reset_at_client_only);
+      if (perspective_ == Perspective::IS_CLIENT) {
+        // Peek possible stateless reset token. Will only be used on decryption
+        // failure.
+        QuicStringPiece remaining = encrypted_reader->PeekRemainingPayload();
+        if (remaining.length() >=
+            sizeof(header->possible_stateless_reset_token)) {
+          header->has_possible_stateless_reset_token = true;
+          memcpy(
+              &header->possible_stateless_reset_token,
+              &remaining.data()[remaining.length() -
+                                sizeof(header->possible_stateless_reset_token)],
+              sizeof(header->possible_stateless_reset_token));
+        }
+      }
     }
   }
 
@@ -1386,6 +1410,8 @@
     const QuicPacketHeader& header) const {
   return perspective_ == Perspective::IS_CLIENT &&
          header.form == SHORT_HEADER &&
+         (!process_stateless_reset_at_client_only_ ||
+          header.has_possible_stateless_reset_token) &&
          visitor_->IsValidStatelessResetToken(
              header.possible_stateless_reset_token);
 }
diff --git a/third_party/quic/core/quic_framer.h b/third_party/quic/core/quic_framer.h
index 8242091..61cd65d 100644
--- a/third_party/quic/core/quic_framer.h
+++ b/third_party/quic/core/quic_framer.h
@@ -769,6 +769,10 @@
   // If not null, framer asks data_producer_ to write stream frame data. Not
   // owned. TODO(fayang): Consider add data producer to framer's constructor.
   QuicStreamFrameDataProducer* data_producer_;
+
+  // Latched value of
+  // quic_reloadable_flag_quic_process_stateless_reset_at_client_only.
+  const bool process_stateless_reset_at_client_only_;
 };
 
 }  // namespace quic
diff --git a/third_party/quic/core/quic_packet_writer.h b/third_party/quic/core/quic_packet_writer.h
index 0399a8b..cf17b83 100644
--- a/third_party/quic/core/quic_packet_writer.h
+++ b/third_party/quic/core/quic_packet_writer.h
@@ -9,28 +9,27 @@
 
 #include "net/third_party/quic/core/quic_packets.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quic/platform/api/quic_socket_address.h"
 
 namespace quic {
 
 struct WriteResult;
 
-class QUIC_EXPORT_PRIVATE PerPacketOptions {
- public:
-  PerPacketOptions() = default;
+struct QUIC_EXPORT_PRIVATE PerPacketOptions {
   virtual ~PerPacketOptions() {}
 
   // Returns a heap-allocated copy of |this|.
-  virtual PerPacketOptions* Clone() const = 0;
+  //
+  // The subclass implementation of this method should look like this:
+  //   return QuicMakeUnique<MyAwesomePerPacketOptions>(*this);
+  //
+  // This method is declared pure virtual in order to ensure the subclasses
+  // would not forget to override it.
+  virtual std::unique_ptr<PerPacketOptions> Clone() const = 0;
 
-  // Sets release time delay in ns for this packet.
-  virtual void SetReleaseTimeDelay(uint64_t release_time_delay_ns) = 0;
-
- private:
-  PerPacketOptions(PerPacketOptions&& other) = delete;
-  PerPacketOptions(const PerPacketOptions&) = delete;
-  PerPacketOptions& operator=(const PerPacketOptions&) = delete;
-  PerPacketOptions& operator=(PerPacketOptions&& other) = delete;
+  // Specifies release time delay for this packet.
+  QuicTime::Delta release_time_delay = QuicTime::Delta::Zero();
 };
 
 // An interface between writers and the entity managing the
diff --git a/third_party/quic/core/quic_packets.cc b/third_party/quic/core/quic_packets.cc
index 0cc59a7..d5f35d1 100644
--- a/third_party/quic/core/quic_packets.cc
+++ b/third_party/quic/core/quic_packets.cc
@@ -70,6 +70,7 @@
       source_connection_id_length(PACKET_0BYTE_CONNECTION_ID),
       reset_flag(false),
       version_flag(false),
+      has_possible_stateless_reset_token(false),
       packet_number_length(PACKET_4BYTE_PACKET_NUMBER),
       version(
           ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)),
diff --git a/third_party/quic/core/quic_packets.h b/third_party/quic/core/quic_packets.h
index e558340..e39db99 100644
--- a/third_party/quic/core/quic_packets.h
+++ b/third_party/quic/core/quic_packets.h
@@ -78,6 +78,9 @@
   // For Google QUIC, version flag in packets from the server means version
   // negotiation packet. For IETF QUIC, version flag means long header.
   bool version_flag;
+  // Indicates whether |possible_stateless_reset_token| contains a valid value
+  // parsed from the packet buffer. IETF QUIC only, always false for GQUIC.
+  bool has_possible_stateless_reset_token;
   QuicPacketNumberLength packet_number_length;
   ParsedQuicVersion version;
   // nonce contains an optional, 32-byte nonce value. If not included in the
@@ -88,6 +91,7 @@
   QuicIetfPacketHeaderForm form;
   // Short packet type is reflected in packet_number_length.
   QuicLongHeaderType long_packet_type;
+  // Only valid if |has_possible_stateless_reset_token| is true.
   // Stores last 16 bytes of a this packet, used to check whether this packet is
   // a stateless reset packet on decryption failure.
   QuicUint128 possible_stateless_reset_token;
diff --git a/third_party/quic/core/quic_sent_packet_manager.cc b/third_party/quic/core/quic_sent_packet_manager.cc
index 0f55c57..1b5422a 100644
--- a/third_party/quic/core/quic_sent_packet_manager.cc
+++ b/third_party/quic/core/quic_sent_packet_manager.cc
@@ -91,7 +91,9 @@
       delayed_ack_time_(
           QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
       rtt_updated_(false),
-      acked_packets_iter_(last_ack_frame_.packets.rbegin()) {
+      acked_packets_iter_(last_ack_frame_.packets.rbegin()),
+      aggregate_acked_stream_frames_(
+          GetQuicReloadableFlag(quic_aggregate_acked_stream_frames)) {
   SetSendAlgorithm(congestion_control_type);
 }
 
@@ -239,6 +241,10 @@
     QuicTime ack_receive_time,
     bool rtt_updated,
     QuicByteCount prior_bytes_in_flight) {
+  if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) {
+    unacked_packets_.NotifyAggregatedStreamFrameAcked(
+        last_ack_frame_.ack_delay_time);
+  }
   InvokeLossDetection(ack_receive_time);
   // Ignore losses in RTO mode.
   if (consecutive_rto_count_ > 0 && !use_new_rto_) {
@@ -389,6 +395,18 @@
       unacked_packets_.RetransmitFrames(*transmission_info, transmission_type);
     } else {
       unacked_packets_.NotifyFramesLost(*transmission_info, transmission_type);
+      if (unacked_packets_.fix_is_useful_for_retransmission()) {
+        if (transmission_type == LOSS_RETRANSMISSION) {
+          // Record the first packet sent after loss, which allows to wait 1
+          // more RTT before giving up on this lost packet.
+          transmission_info->retransmission =
+              unacked_packets_.largest_sent_packet() + 1;
+        } else {
+          // Clear the recorded first packet sent after loss when version or
+          // encryption changes.
+          transmission_info->retransmission = 0;
+        }
+      }
     }
     // Update packet state according to transmission type.
     transmission_info->state =
@@ -474,6 +492,10 @@
 QuicPacketNumber QuicSentPacketManager::GetNewestRetransmission(
     QuicPacketNumber packet_number,
     const QuicTransmissionInfo& transmission_info) const {
+  if (unacked_packets_.fix_is_useful_for_retransmission() &&
+      session_decides_what_to_write()) {
+    return packet_number;
+  }
   QuicPacketNumber retransmission = transmission_info.retransmission;
   while (retransmission != 0) {
     packet_number = retransmission;
@@ -492,17 +514,29 @@
   pending_retransmissions_.erase(newest_transmission);
 
   if (newest_transmission == packet_number) {
-    const bool new_data_acked =
-        unacked_packets_.NotifyFramesAcked(*info, ack_delay_time);
-    if (session_decides_what_to_write() && !new_data_acked &&
-        info->transmission_type != NOT_RETRANSMISSION) {
-      // Record as a spurious retransmission if this packet is a retransmission
-      // and no new data gets acked.
-      QUIC_DVLOG(1) << "Detect spurious retransmitted packet " << packet_number
-                    << " transmission type: "
-                    << QuicUtils::TransmissionTypeToString(
-                           info->transmission_type);
-      RecordSpuriousRetransmissions(*info, packet_number);
+    // Try to aggregate acked stream frames if acked packet is not a
+    // retransmission.
+    const bool fast_path = aggregate_acked_stream_frames_ &&
+                           session_decides_what_to_write() &&
+                           info->transmission_type == NOT_RETRANSMISSION;
+    if (fast_path) {
+      unacked_packets_.MaybeAggregateAckedStreamFrame(*info, ack_delay_time);
+    } else {
+      if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) {
+        unacked_packets_.NotifyAggregatedStreamFrameAcked(ack_delay_time);
+      }
+      const bool new_data_acked =
+          unacked_packets_.NotifyFramesAcked(*info, ack_delay_time);
+      if (session_decides_what_to_write() && !new_data_acked &&
+          info->transmission_type != NOT_RETRANSMISSION) {
+        // Record as a spurious retransmission if this packet is a
+        // retransmission and no new data gets acked.
+        QUIC_DVLOG(1) << "Detect spurious retransmitted packet "
+                      << packet_number << " transmission type: "
+                      << QuicUtils::TransmissionTypeToString(
+                             info->transmission_type);
+        RecordSpuriousRetransmissions(*info, packet_number);
+      }
     }
   } else {
     DCHECK(!session_decides_what_to_write());
diff --git a/third_party/quic/core/quic_sent_packet_manager.h b/third_party/quic/core/quic_sent_packet_manager.h
index 85e7b48..b8be28a 100644
--- a/third_party/quic/core/quic_sent_packet_manager.h
+++ b/third_party/quic/core/quic_sent_packet_manager.h
@@ -553,6 +553,9 @@
   // A reverse iterator of last_ack_frame_.packets. This is reset in
   // OnAckRangeStart, and gradually moves in OnAckRange..
   PacketNumberQueue::const_reverse_iterator acked_packets_iter_;
+
+  // Latched value of quic_reloadable_flag_quic_aggregate_acked_stream_frames.
+  const bool aggregate_acked_stream_frames_;
 };
 
 }  // namespace quic
diff --git a/third_party/quic/core/quic_session.cc b/third_party/quic/core/quic_session.cc
index 41a1d65..e3bdb1d 100644
--- a/third_party/quic/core/quic_session.cc
+++ b/third_party/quic/core/quic_session.cc
@@ -49,9 +49,15 @@
                        perspective() == Perspective::IS_SERVER,
                        nullptr),
       currently_writing_stream_id_(0),
+      largest_static_stream_id_(0),
       goaway_sent_(false),
       goaway_received_(false),
-      control_frame_manager_(this) {}
+      faster_get_stream_(GetQuicReloadableFlag(quic_session_faster_get_stream)),
+      control_frame_manager_(this) {
+  if (faster_get_stream_) {
+    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_session_faster_get_stream);
+  }
+}
 
 void QuicSession::Initialize() {
   connection_->set_visitor(this);
@@ -59,8 +65,12 @@
   connection_->SetDataProducer(this);
   connection_->SetFromConfig(config_);
 
+  // Make sure connection and control frame manager latch the same flag values.
+  connection_->set_donot_retransmit_old_window_updates(
+      control_frame_manager_.donot_retransmit_old_window_updates());
+
   DCHECK_EQ(kCryptoStreamId, GetMutableCryptoStream()->id());
-  static_stream_map_[kCryptoStreamId] = GetMutableCryptoStream();
+  RegisterStaticStream(kCryptoStreamId, GetMutableCryptoStream());
 }
 
 QuicSession::~QuicSession() {
@@ -77,6 +87,14 @@
   QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) << "Still have zombie streams";
 }
 
+void QuicSession::RegisterStaticStream(QuicStreamId id, QuicStream* stream) {
+  static_stream_map_[id] = stream;
+
+  if (faster_get_stream_) {
+    largest_static_stream_id_ = std::max(id, largest_static_stream_id_);
+  }
+}
+
 void QuicSession::OnStreamFrame(const QuicStreamFrame& frame) {
   // TODO(rch) deal with the error case of stream id 0.
   QuicStreamId stream_id = frame.stream_id;
@@ -1012,9 +1030,18 @@
 }
 
 QuicStream* QuicSession::GetStream(QuicStreamId id) const {
-  auto static_stream = static_stream_map_.find(id);
-  if (static_stream != static_stream_map_.end()) {
-    return static_stream->second;
+  if (faster_get_stream_) {
+    if (id <= largest_static_stream_id_) {
+      auto static_stream = static_stream_map_.find(id);
+      if (static_stream != static_stream_map_.end()) {
+        return static_stream->second;
+      }
+    }
+  } else {
+    auto static_stream = static_stream_map_.find(id);
+    if (static_stream != static_stream_map_.end()) {
+      return static_stream->second;
+    }
   }
   auto active_stream = dynamic_stream_map_.find(id);
   if (active_stream != dynamic_stream_map_.end()) {
diff --git a/third_party/quic/core/quic_session.h b/third_party/quic/core/quic_session.h
index b5093e6..00ce187 100644
--- a/third_party/quic/core/quic_session.h
+++ b/third_party/quic/core/quic_session.h
@@ -372,7 +372,9 @@
   // Return true if given stream is peer initiated.
   bool IsIncomingStream(QuicStreamId id) const;
 
-  StaticStreamMap& static_streams() { return static_stream_map_; }
+  // Register (|id|, |stream|) with the static stream map. Override previous
+  // registrations with the same id.
+  void RegisterStaticStream(QuicStreamId id, QuicStream* stream);
   const StaticStreamMap& static_streams() const { return static_stream_map_; }
 
   DynamicStreamMap& dynamic_streams() { return dynamic_stream_map_; }
@@ -541,12 +543,18 @@
   // call stack of OnCanWrite.
   QuicStreamId currently_writing_stream_id_;
 
+  // The largest stream id in |static_stream_map_|.
+  QuicStreamId largest_static_stream_id_;
+
   // Whether a GoAway has been sent.
   bool goaway_sent_;
 
   // Whether a GoAway has been received.
   bool goaway_received_;
 
+  // Latched value of quic_reloadable_flag_quic_session_faster_get_stream.
+  const bool faster_get_stream_;
+
   QuicControlFrameManager control_frame_manager_;
 
   // TODO(fayang): switch to linked_hash_set when chromium supports it. The bool
diff --git a/third_party/quic/core/quic_stream.cc b/third_party/quic/core/quic_stream.cc
index 98c4be6..7f7d0a6 100644
--- a/third_party/quic/core/quic_stream.cc
+++ b/third_party/quic/core/quic_stream.cc
@@ -230,7 +230,6 @@
 }
 
 void QuicStream::SetPriority(SpdyPriority priority) {
-  DCHECK_EQ(0u, stream_bytes_written());
   priority_ = priority;
   session_->UpdateStreamPriority(id(), priority);
 }
diff --git a/third_party/quic/core/quic_transmission_info.h b/third_party/quic/core/quic_transmission_info.h
index 1d93be2..b82b2c6 100644
--- a/third_party/quic/core/quic_transmission_info.h
+++ b/third_party/quic/core/quic_transmission_info.h
@@ -50,6 +50,8 @@
   int16_t num_padding_bytes;
   // Stores the packet number of the next retransmission of this packet.
   // Zero if the packet has not been retransmitted.
+  // TODO(fayang): rename this to first_sent_after_loss_ when deprecating
+  // QUIC_VERSION_41.
   QuicPacketNumber retransmission;
   // The largest_acked in the ack frame, if the packet contains an ack.
   QuicPacketNumber largest_acked;
diff --git a/third_party/quic/core/quic_unacked_packet_map.cc b/third_party/quic/core/quic_unacked_packet_map.cc
index a707bcf..f4692a2 100644
--- a/third_party/quic/core/quic_unacked_packet_map.cc
+++ b/third_party/quic/core/quic_unacked_packet_map.cc
@@ -7,6 +7,7 @@
 #include "net/third_party/quic/core/quic_connection_stats.h"
 #include "net/third_party/quic/core/quic_utils.h"
 #include "net/third_party/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quic/platform/api/quic_flag_utils.h"
 
 namespace quic {
 
@@ -20,7 +21,9 @@
       pending_crypto_packet_count_(0),
       last_crypto_packet_sent_time_(QuicTime::Zero()),
       session_notifier_(nullptr),
-      session_decides_what_to_write_(false) {}
+      session_decides_what_to_write_(false),
+      fix_is_useful_for_retransmission_(
+          GetQuicReloadableFlag(quic_fix_is_useful_for_retrans)) {}
 
 QuicUnackedPacketMap::~QuicUnackedPacketMap() {
   for (QuicTransmissionInfo& transmission_info : unacked_packets_) {
@@ -170,6 +173,9 @@
     QuicTransmissionInfo* info) {
   if (session_decides_what_to_write_) {
     DeleteFrames(&info->retransmittable_frames);
+    if (fix_is_useful_for_retransmission_) {
+      info->retransmission = 0;
+    }
     return;
   }
   while (info->retransmission != 0) {
@@ -218,11 +224,20 @@
 
 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
     const QuicTransmissionInfo& info) const {
-  // Packet may have retransmittable frames, or the data may have been
-  // retransmitted with a new packet number.
-  return HasRetransmittableFrames(info) ||
-         // Allow for an extra 1 RTT before stopping to track old packets.
-         info.retransmission > largest_acked_;
+  if (!session_decides_what_to_write_ || !fix_is_useful_for_retransmission_) {
+    // Packet may have retransmittable frames, or the data may have been
+    // retransmitted with a new packet number.
+    // Allow for an extra 1 RTT before stopping to track old packets.
+    return info.retransmission > largest_acked_ ||
+           HasRetransmittableFrames(info);
+  }
+
+  // Wait for 1 RTT before giving up on the lost packet.
+  if (info.retransmission > largest_acked_) {
+    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_fix_is_useful_for_retrans);
+    return true;
+  }
+  return false;
 }
 
 bool QuicUnackedPacketMap::IsPacketUseless(
@@ -395,6 +410,59 @@
   session_notifier_->RetransmitFrames(info.retransmittable_frames, type);
 }
 
+void QuicUnackedPacketMap::MaybeAggregateAckedStreamFrame(
+    const QuicTransmissionInfo& info,
+    QuicTime::Delta ack_delay) {
+  if (session_notifier_ == nullptr) {
+    return;
+  }
+  for (const auto& frame : info.retransmittable_frames) {
+    // Determine whether acked stream frame can be aggregated.
+    const bool can_aggregate =
+        frame.type == STREAM_FRAME &&
+        frame.stream_frame->stream_id == aggregated_stream_frame_.stream_id &&
+        frame.stream_frame->offset == aggregated_stream_frame_.offset +
+                                          aggregated_stream_frame_.data_length;
+    if (can_aggregate) {
+      // Aggregate stream frame.
+      aggregated_stream_frame_.data_length += frame.stream_frame->data_length;
+      aggregated_stream_frame_.fin = frame.stream_frame->fin;
+      if (aggregated_stream_frame_.fin) {
+        // Notify session notifier aggregated stream frame gets acked if fin is
+        // acked.
+        NotifyAggregatedStreamFrameAcked(ack_delay);
+      }
+      continue;
+    }
+
+    NotifyAggregatedStreamFrameAcked(ack_delay);
+    if (frame.type != STREAM_FRAME || frame.stream_frame->fin) {
+      session_notifier_->OnFrameAcked(frame, ack_delay);
+      continue;
+    }
+
+    // Delay notifying session notifier stream frame gets acked in case it can
+    // be aggregated with following acked ones.
+    aggregated_stream_frame_.stream_id = frame.stream_frame->stream_id;
+    aggregated_stream_frame_.offset = frame.stream_frame->offset;
+    aggregated_stream_frame_.data_length = frame.stream_frame->data_length;
+    aggregated_stream_frame_.fin = frame.stream_frame->fin;
+  }
+}
+
+void QuicUnackedPacketMap::NotifyAggregatedStreamFrameAcked(
+    QuicTime::Delta ack_delay) {
+  if (aggregated_stream_frame_.stream_id == kInvalidStreamId ||
+      session_notifier_ == nullptr) {
+    // Aggregated stream frame is empty.
+    return;
+  }
+  session_notifier_->OnFrameAcked(QuicFrame(&aggregated_stream_frame_),
+                                  ack_delay);
+  // Clear aggregated stream frame.
+  aggregated_stream_frame_.stream_id = kInvalidStreamId;
+}
+
 void QuicUnackedPacketMap::SetSessionDecideWhatToWrite(
     bool session_decides_what_to_write) {
   if (largest_sent_packet_ > 0) {
diff --git a/third_party/quic/core/quic_unacked_packet_map.h b/third_party/quic/core/quic_unacked_packet_map.h
index 656fbca..a12436d 100644
--- a/third_party/quic/core/quic_unacked_packet_map.h
+++ b/third_party/quic/core/quic_unacked_packet_map.h
@@ -165,6 +165,17 @@
   // RTT measurement purposes.
   void RemoveObsoletePackets();
 
+  // Try to aggregate acked contiguous stream frames. For noncontiguous stream
+  // frames or control frames, notify the session notifier they get acked
+  // immediately.
+  void MaybeAggregateAckedStreamFrame(const QuicTransmissionInfo& info,
+                                      QuicTime::Delta ack_delay);
+
+  // Notify the session notifier of any stream data aggregated in
+  // aggregated_stream_frame_.  No effect if the stream frame has an invalid
+  // stream id.
+  void NotifyAggregatedStreamFrameAcked(QuicTime::Delta ack_delay);
+
   // Called to start/stop letting session decide what to write.
   void SetSessionDecideWhatToWrite(bool session_decides_what_to_write);
 
@@ -174,6 +185,10 @@
     return session_decides_what_to_write_;
   }
 
+  bool fix_is_useful_for_retransmission() const {
+    return fix_is_useful_for_retransmission_;
+  }
+
  private:
   // Called when a packet is retransmitted with a new packet number.
   // |old_packet_number| will remain unacked, but will have no
@@ -228,11 +243,18 @@
   // Time that the last unacked crypto packet was sent.
   QuicTime last_crypto_packet_sent_time_;
 
+  // Aggregates acked stream data across multiple acked sent packets to save CPU
+  // by reducing the number of calls to the session notifier.
+  QuicStreamFrame aggregated_stream_frame_;
+
   // Receives notifications of frames being retransmitted or acknowledged.
   SessionNotifierInterface* session_notifier_;
 
   // If true, let session decides what to write.
   bool session_decides_what_to_write_;
+
+  // Latched value of quic_reloadable_flag_quic_fix_is_useful_for_retrans.
+  const bool fix_is_useful_for_retransmission_;
 };
 
 }  // namespace quic
diff --git a/third_party/quic/core/quic_unacked_packet_map_test.cc b/third_party/quic/core/quic_unacked_packet_map_test.cc
index 296d313..8fefd32 100644
--- a/third_party/quic/core/quic_unacked_packet_map_test.cc
+++ b/third_party/quic/core/quic_unacked_packet_map_test.cc
@@ -132,10 +132,10 @@
                                      transmission_type, now_, true);
       return;
     }
-    const QuicTransmissionInfo& info =
-        unacked_packets_.GetTransmissionInfo(old_packet_number);
+    QuicTransmissionInfo* info =
+        unacked_packets_.GetMutableTransmissionInfo(old_packet_number);
     QuicStreamId stream_id = kHeadersStreamId;
-    for (const auto& frame : info.retransmittable_frames) {
+    for (const auto& frame : info->retransmittable_frames) {
       if (frame.type == STREAM_FRAME) {
         stream_id = frame.stream_frame->stream_id;
         break;
@@ -144,6 +144,7 @@
     UpdatePacketState(
         old_packet_number,
         QuicUtils::RetransmissionTypeToPacketState(transmission_type));
+    info->retransmission = new_packet_number;
     SerializedPacket packet(
         CreateRetransmittablePacketForStream(new_packet_number, stream_id));
     unacked_packets_.AddSentPacket(&packet, 0, transmission_type, now_, true);
@@ -355,8 +356,13 @@
   std::vector<QuicPacketNumber> unacked3;
   std::vector<QuicPacketNumber> retransmittable3;
   if (unacked_packets_.session_decides_what_to_write()) {
-    unacked3 = {1, 3, 5, 6};
-    retransmittable3 = {1, 3, 5, 6};
+    if (unacked_packets_.fix_is_useful_for_retransmission()) {
+      unacked3 = {3, 5, 6};
+      retransmittable3 = {3, 5, 6};
+    } else {
+      unacked3 = {1, 3, 5, 6};
+      retransmittable3 = {1, 3, 5, 6};
+    }
   } else {
     unacked3 = {3, 5, 6};
     retransmittable3 = {5, 6};
@@ -375,8 +381,13 @@
   std::vector<QuicPacketNumber> unacked4;
   std::vector<QuicPacketNumber> retransmittable4;
   if (unacked_packets_.session_decides_what_to_write()) {
-    unacked4 = {1, 3, 5, 7};
-    retransmittable4 = {1, 3, 5, 7};
+    if (unacked_packets_.fix_is_useful_for_retransmission()) {
+      unacked4 = {3, 5, 7};
+      retransmittable4 = {3, 5, 7};
+    } else {
+      unacked4 = {1, 3, 5, 7};
+      retransmittable4 = {1, 3, 5, 7};
+    }
   } else {
     unacked4 = {3, 5, 7};
     retransmittable4 = {7};
@@ -453,7 +464,11 @@
 
   std::vector<QuicPacketNumber> unacked4;
   if (unacked_packets_.session_decides_what_to_write()) {
-    unacked4 = {1, 3, 4, 6};
+    if (unacked_packets_.fix_is_useful_for_retransmission()) {
+      unacked4 = {4, 6};
+    } else {
+      unacked4 = {1, 3, 4, 6};
+    }
   } else {
     unacked4 = {4, 6};
   }
@@ -462,7 +477,11 @@
   VerifyInFlightPackets(pending4, QUIC_ARRAYSIZE(pending4));
   std::vector<QuicPacketNumber> retransmittable4;
   if (unacked_packets_.session_decides_what_to_write()) {
-    retransmittable4 = {1, 3, 4, 6};
+    if (unacked_packets_.fix_is_useful_for_retransmission()) {
+      retransmittable4 = {4, 6};
+    } else {
+      retransmittable4 = {1, 3, 4, 6};
+    }
   } else {
     retransmittable4 = {6};
   }
@@ -487,6 +506,74 @@
   EXPECT_EQ(5u, unacked_packets_.largest_sent_packet());
 }
 
+TEST_P(QuicUnackedPacketMapTest, AggregateContiguousAckedStreamFrames) {
+  testing::InSequence s;
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(0);
+  unacked_packets_.NotifyAggregatedStreamFrameAcked(QuicTime::Delta::Zero());
+
+  QuicTransmissionInfo info1;
+  QuicStreamFrame stream_frame1(3, false, 0, 100);
+  info1.retransmittable_frames.push_back(QuicFrame(&stream_frame1));
+
+  QuicTransmissionInfo info2;
+  QuicStreamFrame stream_frame2(3, false, 100, 100);
+  info2.retransmittable_frames.push_back(QuicFrame(&stream_frame2));
+
+  QuicTransmissionInfo info3;
+  QuicStreamFrame stream_frame3(3, false, 200, 100);
+  info3.retransmittable_frames.push_back(QuicFrame(&stream_frame3));
+
+  QuicTransmissionInfo info4;
+  QuicStreamFrame stream_frame4(3, true, 300, 0);
+  info4.retransmittable_frames.push_back(QuicFrame(&stream_frame4));
+
+  // Verify stream frames are aggregated.
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(0);
+  unacked_packets_.MaybeAggregateAckedStreamFrame(info1,
+                                                  QuicTime::Delta::Zero());
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(0);
+  unacked_packets_.MaybeAggregateAckedStreamFrame(info2,
+                                                  QuicTime::Delta::Zero());
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(0);
+  unacked_packets_.MaybeAggregateAckedStreamFrame(info3,
+                                                  QuicTime::Delta::Zero());
+
+  // Verify aggregated stream frame gets acked since fin is acked.
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(1);
+  unacked_packets_.MaybeAggregateAckedStreamFrame(info4,
+                                                  QuicTime::Delta::Zero());
+}
+
+TEST_P(QuicUnackedPacketMapTest, CannotAggregateAckedControlFrames) {
+  testing::InSequence s;
+  QuicWindowUpdateFrame window_update(1, 5, 100);
+  QuicStreamFrame stream_frame1(3, false, 0, 100);
+  QuicStreamFrame stream_frame2(3, false, 100, 100);
+  QuicBlockedFrame blocked(2, 5);
+  QuicGoAwayFrame go_away(3, QUIC_PEER_GOING_AWAY, 5, "Going away.");
+
+  QuicTransmissionInfo info1;
+  info1.retransmittable_frames.push_back(QuicFrame(&window_update));
+  info1.retransmittable_frames.push_back(QuicFrame(&stream_frame1));
+  info1.retransmittable_frames.push_back(QuicFrame(&stream_frame2));
+
+  QuicTransmissionInfo info2;
+  info2.retransmittable_frames.push_back(QuicFrame(&blocked));
+  info2.retransmittable_frames.push_back(QuicFrame(&go_away));
+
+  // Verify 2 contiguous stream frames are aggregated.
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(1);
+  unacked_packets_.MaybeAggregateAckedStreamFrame(info1,
+                                                  QuicTime::Delta::Zero());
+  // Verify aggregated stream frame gets acked.
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(3);
+  unacked_packets_.MaybeAggregateAckedStreamFrame(info2,
+                                                  QuicTime::Delta::Zero());
+
+  EXPECT_CALL(notifier_, OnFrameAcked(_, _)).Times(0);
+  unacked_packets_.NotifyAggregatedStreamFrameAcked(QuicTime::Delta::Zero());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/third_party/quic/quartc/quartc_packet_writer.cc b/third_party/quic/quartc/quartc_packet_writer.cc
index ba1709d..340f23e 100644
--- a/third_party/quic/quartc/quartc_packet_writer.cc
+++ b/third_party/quic/quartc/quartc_packet_writer.cc
@@ -64,4 +64,9 @@
   return WriteResult(WRITE_STATUS_OK, 0);
 }
 
+void QuartcPacketWriter::SetPacketTransportDelegate(
+    QuartcPacketTransport::Delegate* delegate) {
+  packet_transport_->SetDelegate(delegate);
+}
+
 }  // namespace quic
diff --git a/third_party/quic/quartc/quartc_packet_writer.h b/third_party/quic/quartc/quartc_packet_writer.h
index a4dca96..cc7b707 100644
--- a/third_party/quic/quartc/quartc_packet_writer.h
+++ b/third_party/quic/quartc/quartc_packet_writer.h
@@ -21,6 +21,20 @@
     QuicPacketNumber packet_number;
   };
 
+  // Delegate for packet transport callbacks.  Note that the delegate is not
+  // thread-safe.  Packet transport implementations must ensure that callbacks
+  // are synchronized with all other work done by QUIC.
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+
+    // Called whenever the transport can write.
+    virtual void OnTransportCanWrite() = 0;
+
+    // Called when the transport receives a packet.
+    virtual void OnTransportReceived(const char* data, size_t data_len) = 0;
+  };
+
   virtual ~QuartcPacketTransport() {}
 
   // Called by the QuartcPacketWriter when writing packets to the network.
@@ -28,6 +42,13 @@
   virtual int Write(const char* buffer,
                     size_t buf_len,
                     const PacketInfo& info) = 0;
+
+  // Sets the delegate which must be called when the transport can write or
+  // a packet is received.  QUIC sets |delegate| to a nonnull pointer when it
+  // is ready to process incoming packets and sets |delegate| to nullptr before
+  // QUIC is deleted.  Implementations may assume |delegate| remains valid until
+  // it is set to nullptr.
+  virtual void SetDelegate(Delegate* delegate) = 0;
 };
 
 // Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a
@@ -75,6 +96,8 @@
   // be set in order to attach packet info (eg. packet numbers) to writes.
   void set_connection(QuicConnection* connection) { connection_ = connection; }
 
+  void SetPacketTransportDelegate(QuartcPacketTransport::Delegate* delegate);
+
  private:
   // QuartcPacketWriter will not own the transport.
   QuartcPacketTransport* packet_transport_;
diff --git a/third_party/quic/quartc/quartc_session.cc b/third_party/quic/quartc/quartc_session.cc
index 602ea19..a45bfda 100644
--- a/third_party/quic/quartc/quartc_session.cc
+++ b/third_party/quic/quartc/quartc_session.cc
@@ -203,12 +203,33 @@
   }
 }
 
+void QuartcSession::OnCongestionWindowChange(QuicTime now) {
+  DCHECK(session_delegate_);
+  const RttStats* rtt_stats = connection_->sent_packet_manager().GetRttStats();
+
+  QuicBandwidth bandwidth_estimate =
+      connection_->sent_packet_manager().BandwidthEstimate();
+
+  QuicByteCount in_flight =
+      connection_->sent_packet_manager().GetBytesInFlight();
+  QuicBandwidth pacing_rate =
+      connection_->sent_packet_manager().GetSendAlgorithm()->PacingRate(
+          in_flight);
+
+  session_delegate_->OnCongestionControlChange(bandwidth_estimate, pacing_rate,
+                                               rtt_stats->latest_rtt());
+}
+
 void QuartcSession::OnConnectionClosed(QuicErrorCode error,
                                        const QuicString& error_details,
                                        ConnectionCloseSource source) {
   QuicSession::OnConnectionClosed(error, error_details, source);
   DCHECK(session_delegate_);
   session_delegate_->OnConnectionClosed(error, error_details, source);
+
+  // The session may be deleted after OnConnectionClosed(), so |this| must be
+  // removed from the packet transport's delegate before it is deleted.
+  packet_writer_->SetPacketTransportDelegate(nullptr);
 }
 
 void QuartcSession::SetPreSharedKey(QuicStringPiece key) {
@@ -240,6 +261,10 @@
     crypto_stream_.reset(crypto_stream);
     QuicSession::Initialize();
   }
+
+  // QUIC is ready to process incoming packets after QuicSession::Initialize().
+  // Set the packet transport delegate to begin receiving packets.
+  packet_writer_->SetPacketTransportDelegate(this);
 }
 
 void QuartcSession::CloseConnection(const QuicString& details) {
@@ -263,11 +288,10 @@
   }
 }
 
-bool QuartcSession::OnTransportReceived(const char* data, size_t data_len) {
+void QuartcSession::OnTransportReceived(const char* data, size_t data_len) {
   QuicReceivedPacket packet(data, data_len, clock_->Now());
   ProcessUdpPacket(connection()->self_address(), connection()->peer_address(),
                    packet);
-  return true;
 }
 
 void QuartcSession::OnProofValid(
diff --git a/third_party/quic/quartc/quartc_session.h b/third_party/quic/quartc/quartc_session.h
index 82a4333..edd3802 100644
--- a/third_party/quic/quartc/quartc_session.h
+++ b/third_party/quic/quartc/quartc_session.h
@@ -32,6 +32,7 @@
 // QuartcSession owns and manages a QUIC connection.
 class QUIC_EXPORT_PRIVATE QuartcSession
     : public QuicSession,
+      public QuartcPacketTransport::Delegate,
       public QuicCryptoClientStream::ProofHandler {
  public:
   QuartcSession(std::unique_ptr<QuicConnection> connection,
@@ -55,6 +56,8 @@
   void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
 
   // QuicConnectionVisitorInterface overrides.
+  void OnCongestionWindowChange(QuicTime now) override;
+
   void OnConnectionClosed(QuicErrorCode error,
                           const QuicString& error_details,
                           ConnectionCloseSource source) override;
@@ -97,6 +100,11 @@
     // Called when a new stream is received from the remote endpoint.
     virtual void OnIncomingStream(QuartcStream* stream) = 0;
 
+    // Called when network parameters change in response to an ack frame.
+    virtual void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
+                                           QuicBandwidth pacing_rate,
+                                           QuicTime::Delta latest_rtt) = 0;
+
     // Called when the connection is closed. This means all of the streams will
     // be closed and no new streams can be created.
     virtual void OnConnectionClosed(QuicErrorCode error_code,
@@ -110,11 +118,11 @@
   void SetDelegate(Delegate* session_delegate);
 
   // Called when CanWrite() changes from false to true.
-  void OnTransportCanWrite();
+  void OnTransportCanWrite() override;
 
   // Called when a packet has been received and should be handled by the
   // QuicConnection.
-  bool OnTransportReceived(const char* data, size_t data_len);
+  void OnTransportReceived(const char* data, size_t data_len) override;
 
   // ProofHandler overrides.
   void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
diff --git a/third_party/quic/quartc/quartc_session_test.cc b/third_party/quic/quartc/quartc_session_test.cc
index f098b07..1b2d988 100644
--- a/third_party/quic/quartc/quartc_session_test.cc
+++ b/third_party/quic/quartc/quartc_session_test.cc
@@ -110,38 +110,41 @@
       alarms_{alarm_later_};
 };
 
-// Used by the FakeTransportChannel.
-class FakeTransportChannelObserver {
+// Fake QuartcPacketTransport.  Assumes all methods run on the main test thread.
+class FakePacketTransport : public QuartcPacketTransport {
  public:
-  virtual ~FakeTransportChannelObserver() {}
-
-  // Called when the other peer is trying to send message.
-  virtual void OnTransportChannelReadPacket(const QuicString& data) = 0;
-};
-
-// Simulate the P2P communication transport. Used by the
-// QuartcSession::Transport.
-class FakeTransportChannel : QuicAlarm::Delegate {
- public:
-  explicit FakeTransportChannel(QuicAlarmFactory* alarm_factory,
-                                MockClock* clock)
+  explicit FakePacketTransport(QuicAlarmFactory* alarm_factory,
+                               MockClock* clock)
       : alarm_(alarm_factory->CreateAlarm(new AlarmDelegate(this))),
         clock_(clock) {}
 
-  void SetDestination(FakeTransportChannel* dest) {
+  void SetDestination(FakePacketTransport* dest) {
     if (!dest_) {
       dest_ = dest;
       dest_->SetDestination(this);
     }
+    if (delegate_) {
+      delegate_->OnTransportCanWrite();
+    }
   }
 
-  int SendPacket(const char* data, size_t len) {
+  int Write(const char* data,
+            size_t len,
+            const QuartcPacketTransport::PacketInfo& info) {
     // If the destination is not set.
     if (!dest_) {
       return -1;
     }
+
     // Advance the time 10us to ensure the RTT is never 0ms.
     clock_->AdvanceTime(QuicTime::Delta::FromMicroseconds(10));
+
+    if (packets_to_lose_ > 0) {
+      --packets_to_lose_;
+      return len;
+    }
+    last_packet_number_ = info.packet_number;
+
     if (async_) {
       packet_queue_.emplace_back(data, len);
       alarm_->Cancel();
@@ -152,32 +155,40 @@
     return static_cast<int>(len);
   }
 
-  FakeTransportChannelObserver* observer() { return observer_; }
+  QuartcPacketTransport::Delegate* delegate() { return delegate_; }
 
-  void SetObserver(FakeTransportChannelObserver* observer) {
-    observer_ = observer;
+  void SetDelegate(QuartcPacketTransport::Delegate* delegate) override {
+    delegate_ = delegate;
+    if (dest_ && delegate_) {
+      delegate_->OnTransportCanWrite();
+    }
   }
 
   void SetAsync(bool async) { async_ = async; }
 
+  QuicPacketNumber last_packet_number() { return last_packet_number_; }
+
+  void set_packets_to_lose(QuicPacketCount count) { packets_to_lose_ = count; }
+
  private:
   class AlarmDelegate : public QuicAlarm::Delegate {
    public:
-    explicit AlarmDelegate(FakeTransportChannel* channel) : channel_(channel) {}
+    explicit AlarmDelegate(FakePacketTransport* transport)
+        : transport_(transport) {}
 
-    void OnAlarm() override { channel_->OnAlarm(); }
+    void OnAlarm() override { transport_->OnAlarm(); }
 
    private:
-    FakeTransportChannel* channel_;
+    FakePacketTransport* transport_;
   };
 
   void Send(const QuicString& data) {
     DCHECK(dest_);
-    DCHECK(dest_->observer());
-    dest_->observer()->OnTransportChannelReadPacket(data);
+    DCHECK(dest_->delegate());
+    dest_->delegate()->OnTransportReceived(data.data(), data.size());
   }
 
-  void OnAlarm() override {
+  void OnAlarm() {
     QUIC_LOG(WARNING) << "Sending packet: " << packet_queue_.front();
     Send(packet_queue_.front());
     packet_queue_.pop_front();
@@ -189,9 +200,9 @@
   }
 
   // The writing destination of this channel.
-  FakeTransportChannel* dest_ = nullptr;
-  // The observer of this channel. Called when the received the data.
-  FakeTransportChannelObserver* observer_ = nullptr;
+  FakePacketTransport* dest_ = nullptr;
+  // Packet transport delegate.  Called when data is received.
+  QuartcPacketTransport::Delegate* delegate_ = nullptr;
   // If async, will send packets by running asynchronous tasks.
   bool async_ = false;
   // If async, packets are queued here to send.
@@ -200,31 +211,7 @@
   QuicArenaScopedPtr<QuicAlarm> alarm_;
   // The test clock.  Used to ensure the RTT is not 0.
   MockClock* clock_;
-};
 
-// Used by the QuartcPacketWriter.
-class FakeTransport : public QuartcPacketTransport {
- public:
-  explicit FakeTransport(FakeTransportChannel* channel) : channel_(channel) {}
-
-  int Write(const char* buffer,
-            size_t buf_len,
-            const PacketInfo& info) override {
-    DCHECK(channel_);
-    if (packets_to_lose_ > 0) {
-      --packets_to_lose_;
-      return buf_len;
-    }
-    last_packet_number_ = info.packet_number;
-    return channel_->SendPacket(buffer, buf_len);
-  }
-
-  QuicPacketNumber last_packet_number() { return last_packet_number_; }
-
-  void set_packets_to_lose(QuicPacketCount count) { packets_to_lose_ = count; }
-
- private:
-  FakeTransportChannel* channel_;
   QuicPacketNumber last_packet_number_;
   QuicPacketCount packets_to_lose_ = 0;
 };
@@ -249,6 +236,10 @@
     last_incoming_stream_->SetDelegate(stream_delegate_);
   }
 
+  void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
+                                 QuicBandwidth pacing_rate,
+                                 QuicTime::Delta latest_rtt) override {}
+
   QuartcStream* incoming_stream() { return last_incoming_stream_; }
 
   bool connected() { return connected_; }
@@ -273,6 +264,7 @@
 
   void OnBufferChanged(QuartcStream* stream) override {}
 
+  bool has_data() { return !received_data_.empty(); }
   std::map<QuicStreamId, QuicString> data() { return received_data_; }
 
   QuicRstStreamErrorCode stream_error(QuicStreamId id) { return errors_[id]; }
@@ -282,50 +274,6 @@
   std::map<QuicStreamId, QuicRstStreamErrorCode> errors_;
 };
 
-class QuartcSessionForTest : public QuartcSession,
-                             public FakeTransportChannelObserver {
- public:
-  QuartcSessionForTest(std::unique_ptr<QuicConnection> connection,
-                       const QuicConfig& config,
-                       const QuicString& remote_fingerprint_value,
-                       Perspective perspective,
-                       QuicConnectionHelperInterface* helper,
-                       QuicClock* clock,
-                       std::unique_ptr<QuartcPacketWriter> writer)
-      : QuartcSession(std::move(connection),
-                      config,
-                      remote_fingerprint_value,
-                      perspective,
-                      helper,
-                      clock,
-                      std::move(writer)) {
-    stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
-    session_delegate_ =
-        QuicMakeUnique<FakeQuartcSessionDelegate>((stream_delegate_.get()));
-
-    SetDelegate(session_delegate_.get());
-  }
-
-  // QuartcPacketWriter override.
-  void OnTransportChannelReadPacket(const QuicString& data) override {
-    OnTransportReceived(data.c_str(), data.length());
-  }
-
-  std::map<QuicStreamId, QuicString> data() { return stream_delegate_->data(); }
-
-  bool has_data() { return !data().empty(); }
-
-  FakeQuartcSessionDelegate* session_delegate() {
-    return session_delegate_.get();
-  }
-
-  FakeQuartcStreamDelegate* stream_delegate() { return stream_delegate_.get(); }
-
- private:
-  std::unique_ptr<FakeQuartcStreamDelegate> stream_delegate_;
-  std::unique_ptr<FakeQuartcSessionDelegate> session_delegate_;
-};
-
 class QuartcSessionTest : public QuicTest,
                           public QuicConnectionHelperInterface {
  public:
@@ -334,25 +282,27 @@
   void Init() {
     // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
-    client_channel_ =
-        QuicMakeUnique<FakeTransportChannel>(&alarm_factory_, &clock_);
-    server_channel_ =
-        QuicMakeUnique<FakeTransportChannel>(&alarm_factory_, &clock_);
+    client_transport_ =
+        QuicMakeUnique<FakePacketTransport>(&alarm_factory_, &clock_);
+    server_transport_ =
+        QuicMakeUnique<FakePacketTransport>(&alarm_factory_, &clock_);
     // Make the channel asynchronous so that two peer will not keep calling each
     // other when they exchange information.
-    client_channel_->SetAsync(true);
-    client_channel_->SetDestination(server_channel_.get());
-
-    client_transport_ = QuicMakeUnique<FakeTransport>(client_channel_.get());
-    server_transport_ = QuicMakeUnique<FakeTransport>(server_channel_.get());
+    client_transport_->SetAsync(true);
+    client_transport_->SetDestination(server_transport_.get());
 
     client_writer_ = QuicMakeUnique<QuartcPacketWriter>(client_transport_.get(),
                                                         kDefaultMaxPacketSize);
     server_writer_ = QuicMakeUnique<QuartcPacketWriter>(server_transport_.get(),
                                                         kDefaultMaxPacketSize);
 
-    client_writer_->SetWritable();
-    server_writer_->SetWritable();
+    client_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
+    client_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>(
+        client_stream_delegate_.get());
+
+    server_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>();
+    server_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>(
+        server_stream_delegate_.get());
   }
 
   // The parameters are used to control whether the handshake will success or
@@ -361,23 +311,22 @@
     Init();
     client_peer_ =
         CreateSession(Perspective::IS_CLIENT, std::move(client_writer_));
+    client_peer_->SetDelegate(client_session_delegate_.get());
     server_peer_ =
         CreateSession(Perspective::IS_SERVER, std::move(server_writer_));
-
-    client_channel_->SetObserver(client_peer_.get());
-    server_channel_->SetObserver(server_peer_.get());
+    server_peer_->SetDelegate(server_session_delegate_.get());
   }
 
-  std::unique_ptr<QuartcSessionForTest> CreateSession(
+  std::unique_ptr<QuartcSession> CreateSession(
       Perspective perspective,
       std::unique_ptr<QuartcPacketWriter> writer) {
     std::unique_ptr<QuicConnection> quic_connection =
         CreateConnection(perspective, writer.get());
     QuicString remote_fingerprint_value = "value";
     QuicConfig config;
-    return QuicMakeUnique<QuartcSessionForTest>(
-        std::move(quic_connection), config, remote_fingerprint_value,
-        perspective, this, &clock_, std::move(writer));
+    return QuicMakeUnique<QuartcSession>(std::move(quic_connection), config,
+                                         remote_fingerprint_value, perspective,
+                                         this, &clock_, std::move(writer));
   }
 
   std::unique_ptr<QuicConnection> CreateConnection(Perspective perspective,
@@ -413,7 +362,7 @@
     ASSERT_NE(nullptr, outgoing_stream);
     EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
 
-    outgoing_stream->SetDelegate(server_peer_->stream_delegate());
+    outgoing_stream->SetDelegate(server_stream_delegate_.get());
 
     // Send a test message from peer 1 to peer 2.
     char kTestMessage[] = "Hello";
@@ -423,15 +372,14 @@
     RunTasks();
 
     // Wait for peer 2 to receive messages.
-    ASSERT_TRUE(client_peer_->has_data());
+    ASSERT_TRUE(client_stream_delegate_->has_data());
 
-    QuartcStream* incoming =
-        client_peer_->session_delegate()->incoming_stream();
+    QuartcStream* incoming = client_session_delegate_->incoming_stream();
     ASSERT_TRUE(incoming);
     EXPECT_EQ(incoming->id(), stream_id);
     EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
 
-    EXPECT_EQ(client_peer_->data()[stream_id], kTestMessage);
+    EXPECT_EQ(client_stream_delegate_->data()[stream_id], kTestMessage);
     // Send a test message from peer 2 to peer 1.
     char kTestResponse[] = "Response";
     test::QuicTestMemSliceVector response(
@@ -439,15 +387,15 @@
     incoming->WriteMemSlices(response.span(), /*fin=*/false);
     RunTasks();
     // Wait for peer 1 to receive messages.
-    ASSERT_TRUE(server_peer_->has_data());
+    ASSERT_TRUE(server_stream_delegate_->has_data());
 
-    EXPECT_EQ(server_peer_->data()[stream_id], kTestResponse);
+    EXPECT_EQ(server_stream_delegate_->data()[stream_id], kTestResponse);
   }
 
   // Test that client and server are not connected after handshake failure.
   void TestDisconnectAfterFailedHandshake() {
-    EXPECT_TRUE(!client_peer_->session_delegate()->connected());
-    EXPECT_TRUE(!server_peer_->session_delegate()->connected());
+    EXPECT_TRUE(!client_session_delegate_->connected());
+    EXPECT_TRUE(!server_session_delegate_->connected());
 
     EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
     EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
@@ -471,14 +419,17 @@
   FakeAlarmFactory alarm_factory_{&clock_};
   SimpleBufferAllocator buffer_allocator_;
 
-  std::unique_ptr<FakeTransportChannel> client_channel_;
-  std::unique_ptr<FakeTransportChannel> server_channel_;
-  std::unique_ptr<FakeTransport> client_transport_;
-  std::unique_ptr<FakeTransport> server_transport_;
+  std::unique_ptr<FakePacketTransport> client_transport_;
+  std::unique_ptr<FakePacketTransport> server_transport_;
   std::unique_ptr<QuartcPacketWriter> client_writer_;
   std::unique_ptr<QuartcPacketWriter> server_writer_;
-  std::unique_ptr<QuartcSessionForTest> client_peer_;
-  std::unique_ptr<QuartcSessionForTest> server_peer_;
+  std::unique_ptr<QuartcSession> client_peer_;
+  std::unique_ptr<QuartcSession> server_peer_;
+
+  std::unique_ptr<FakeQuartcStreamDelegate> client_stream_delegate_;
+  std::unique_ptr<FakeQuartcSessionDelegate> client_session_delegate_;
+  std::unique_ptr<FakeQuartcStreamDelegate> server_stream_delegate_;
+  std::unique_ptr<FakeQuartcSessionDelegate> server_session_delegate_;
 };
 
 TEST_F(QuartcSessionTest, StreamConnection) {
@@ -513,7 +464,7 @@
 
   uint32_t id = stream->id();
   EXPECT_FALSE(client_peer_->IsClosedStream(id));
-  stream->SetDelegate(client_peer_->stream_delegate());
+  stream->SetDelegate(client_stream_delegate_.get());
   client_peer_->CancelStream(id);
   EXPECT_EQ(stream->stream_error(),
             QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
@@ -527,7 +478,7 @@
   ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
 
   QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
-  stream->SetDelegate(client_peer_->stream_delegate());
+  stream->SetDelegate(client_stream_delegate_.get());
 
   char kClientMessage[] = "Hello";
   test::QuicTestMemSliceVector stream_data(
@@ -548,9 +499,9 @@
   ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
 
   client_peer_->CloseConnection("Connection closed by client");
-  EXPECT_FALSE(client_peer_->session_delegate()->connected());
+  EXPECT_FALSE(client_session_delegate_->connected());
   RunTasks();
-  EXPECT_FALSE(server_peer_->session_delegate()->connected());
+  EXPECT_FALSE(server_session_delegate_->connected());
 }
 
 TEST_F(QuartcSessionTest, StreamRetransmissionEnabled) {
@@ -561,7 +512,7 @@
 
   QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
   QuicStreamId stream_id = stream->id();
-  stream->SetDelegate(client_peer_->stream_delegate());
+  stream->SetDelegate(client_stream_delegate_.get());
   stream->set_cancel_on_loss(false);
 
   client_transport_->set_packets_to_lose(1);
@@ -573,8 +524,8 @@
   RunTasks();
 
   // Stream data should make it despite packet loss.
-  ASSERT_TRUE(server_peer_->has_data());
-  EXPECT_EQ(server_peer_->data()[stream_id], kClientMessage);
+  ASSERT_TRUE(server_stream_delegate_->has_data());
+  EXPECT_EQ(server_stream_delegate_->data()[stream_id], kClientMessage);
 }
 
 TEST_F(QuartcSessionTest, StreamRetransmissionDisabled) {
@@ -585,7 +536,7 @@
 
   QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
   QuicStreamId stream_id = stream->id();
-  stream->SetDelegate(client_peer_->stream_delegate());
+  stream->SetDelegate(client_stream_delegate_.get());
   stream->set_cancel_on_loss(true);
 
   client_transport_->set_packets_to_lose(1);
@@ -598,7 +549,7 @@
 
   // Send another packet to trigger loss detection.
   QuartcStream* stream_1 = client_peer_->CreateOutgoingDynamicStream();
-  stream_1->SetDelegate(client_peer_->stream_delegate());
+  stream_1->SetDelegate(client_stream_delegate_.get());
 
   char kMessage1[] = "Second message";
   test::QuicTestMemSliceVector stream_data_1(
@@ -608,13 +559,13 @@
 
   // QUIC should try to retransmit the first stream by loss detection.  Instead,
   // it will cancel itself.
-  EXPECT_THAT(server_peer_->data()[stream_id], testing::IsEmpty());
+  EXPECT_THAT(server_stream_delegate_->data()[stream_id], testing::IsEmpty());
 
   EXPECT_TRUE(client_peer_->IsClosedStream(stream_id));
   EXPECT_TRUE(server_peer_->IsClosedStream(stream_id));
-  EXPECT_EQ(client_peer_->stream_delegate()->stream_error(stream_id),
+  EXPECT_EQ(client_stream_delegate_->stream_error(stream_id),
             QUIC_STREAM_CANCELLED);
-  EXPECT_EQ(server_peer_->stream_delegate()->stream_error(stream_id),
+  EXPECT_EQ(server_stream_delegate_->stream_error(stream_id),
             QUIC_STREAM_CANCELLED);
 }
 
diff --git a/third_party/quic/test_tools/packet_dropping_test_writer.cc b/third_party/quic/test_tools/packet_dropping_test_writer.cc
index 5f76151..921d0f8 100644
--- a/third_party/quic/test_tools/packet_dropping_test_writer.cc
+++ b/third_party/quic/test_tools/packet_dropping_test_writer.cc
@@ -144,7 +144,7 @@
     }
     std::unique_ptr<PerPacketOptions> delayed_options;
     if (options != nullptr) {
-      delayed_options.reset(options->Clone());
+      delayed_options = options->Clone();
     }
     delayed_packets_.push_back(
         DelayedWrite(buffer, buf_len, self_address, peer_address,
diff --git a/third_party/quic/test_tools/packet_reordering_writer.cc b/third_party/quic/test_tools/packet_reordering_writer.cc
index f14ae43..c4436be 100644
--- a/third_party/quic/test_tools/packet_reordering_writer.cc
+++ b/third_party/quic/test_tools/packet_reordering_writer.cc
@@ -37,7 +37,7 @@
   delayed_self_address_ = self_address;
   delayed_peer_address_ = peer_address;
   if (options != nullptr) {
-    delayed_options_.reset(options->Clone());
+    delayed_options_ = options->Clone();
   }
   delay_next_ = false;
   return WriteResult(WRITE_STATUS_OK, buf_len);
diff --git a/third_party/quic/test_tools/quic_connection_peer.cc b/third_party/quic/test_tools/quic_connection_peer.cc
index b7615fe..902c703 100644
--- a/third_party/quic/test_tools/quic_connection_peer.cc
+++ b/third_party/quic/test_tools/quic_connection_peer.cc
@@ -312,5 +312,13 @@
   connection->version_negotiation_state_ = QuicConnection::NEGOTIATED_VERSION;
 }
 
+// static
+void QuicConnectionPeer::SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames(
+    QuicConnection* connection,
+    size_t new_value) {
+  connection->max_consecutive_num_packets_with_no_retransmittable_frames_ =
+      new_value;
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/third_party/quic/test_tools/quic_connection_peer.h b/third_party/quic/test_tools/quic_connection_peer.h
index b5ad7ae..eaaa0d4 100644
--- a/third_party/quic/test_tools/quic_connection_peer.h
+++ b/third_party/quic/test_tools/quic_connection_peer.h
@@ -130,6 +130,9 @@
                                    QuicPacketCount max_tracked_packets);
   static void SetSessionDecidesWhatToWrite(QuicConnection* connection);
   static void SetNegotiatedVersion(QuicConnection* connection);
+  static void SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames(
+      QuicConnection* connection,
+      size_t new_value);
 };
 
 }  // namespace test
diff --git a/third_party/quic/test_tools/quic_server_session_base_peer.h b/third_party/quic/test_tools/quic_server_session_base_peer.h
index 6f129f4..60ee7e1 100644
--- a/third_party/quic/test_tools/quic_server_session_base_peer.h
+++ b/third_party/quic/test_tools/quic_server_session_base_peer.h
@@ -19,7 +19,7 @@
   static void SetCryptoStream(QuicServerSessionBase* s,
                               QuicCryptoServerStream* crypto_stream) {
     s->crypto_stream_.reset(crypto_stream);
-    s->static_streams()[kCryptoStreamId] = crypto_stream;
+    s->RegisterStaticStream(kCryptoStreamId, crypto_stream);
   }
   static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) {
     return s->bandwidth_resumption_enabled_;
diff --git a/third_party/quic/test_tools/quic_session_peer.cc b/third_party/quic/test_tools/quic_session_peer.cc
index a5202e9..ff9faf1 100644
--- a/third_party/quic/test_tools/quic_session_peer.cc
+++ b/third_party/quic/test_tools/quic_session_peer.cc
@@ -61,7 +61,7 @@
 // static
 QuicSession::StaticStreamMap& QuicSessionPeer::static_streams(
     QuicSession* session) {
-  return session->static_streams();
+  return session->static_stream_map_;
 }
 
 // static
diff --git a/third_party/quic/test_tools/quic_spdy_session_peer.cc b/third_party/quic/test_tools/quic_spdy_session_peer.cc
index 60b0359..aa7301e 100644
--- a/third_party/quic/test_tools/quic_spdy_session_peer.cc
+++ b/third_party/quic/test_tools/quic_spdy_session_peer.cc
@@ -20,7 +20,7 @@
                                            QuicHeadersStream* headers_stream) {
   session->headers_stream_.reset(headers_stream);
   if (headers_stream != nullptr) {
-    session->static_streams()[headers_stream->id()] = headers_stream;
+    session->RegisterStaticStream(headers_stream->id(), headers_stream);
   }
 }
 
diff --git a/third_party/quic/tools/quic_simple_server_session_test.cc b/third_party/quic/tools/quic_simple_server_session_test.cc
index c9c76aa..47bf5ba 100644
--- a/third_party/quic/tools/quic_simple_server_session_test.cc
+++ b/third_party/quic/tools/quic_simple_server_session_test.cc
@@ -55,7 +55,7 @@
   static void SetCryptoStream(QuicSimpleServerSession* s,
                               QuicCryptoServerStream* crypto_stream) {
     s->crypto_stream_.reset(crypto_stream);
-    s->static_streams()[kCryptoStreamId] = crypto_stream;
+    s->RegisterStaticStream(kCryptoStreamId, crypto_stream);
   }
 
   static QuicSpdyStream* CreateIncomingDynamicStream(QuicSimpleServerSession* s,