Add KeyUpdateReason enum to KeyUpdate call & OnKeyUpdate callbacks.

PiperOrigin-RevId: 337886250
Change-Id: I1a8ebf0212f8c3b9a80d47bc93c243f6cd2c128c
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc
index 33f6c0e..e469e0d 100644
--- a/quic/core/chlo_extractor.cc
+++ b/quic/core/chlo_extractor.cc
@@ -82,7 +82,7 @@
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
       const QuicIetfStatelessResetPacket& /*packet*/) override {}
-  void OnKeyUpdate() override;
+  void OnKeyUpdate(KeyUpdateReason /*reason*/) override;
   void OnDecryptedFirstPacketInKeyPhase() override;
   std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
       override;
@@ -315,7 +315,7 @@
   return true;
 }
 
-void ChloFramerVisitor::OnKeyUpdate() {}
+void ChloFramerVisitor::OnKeyUpdate(KeyUpdateReason /*reason*/) {}
 
 void ChloFramerVisitor::OnDecryptedFirstPacketInKeyPhase() {}
 
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 025e257..fe58711 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -4833,14 +4833,16 @@
   ASSERT_TRUE(client_connection);
   EXPECT_EQ(0u, client_connection->GetStats().key_update_count);
 
-  EXPECT_TRUE(client_connection->InitiateKeyUpdate());
+  EXPECT_TRUE(
+      client_connection->InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
   SendSynchronousFooRequestAndCheckResponse();
   EXPECT_EQ(1u, client_connection->GetStats().key_update_count);
 
   SendSynchronousFooRequestAndCheckResponse();
   EXPECT_EQ(1u, client_connection->GetStats().key_update_count);
 
-  EXPECT_TRUE(client_connection->InitiateKeyUpdate());
+  EXPECT_TRUE(
+      client_connection->InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
   SendSynchronousFooRequestAndCheckResponse();
   EXPECT_EQ(2u, client_connection->GetStats().key_update_count);
 
@@ -4883,7 +4885,8 @@
             // key phase, wait a bit and try again.
             return false;
           }
-          EXPECT_TRUE(server_connection->InitiateKeyUpdate());
+          EXPECT_TRUE(server_connection->InitiateKeyUpdate(
+              KeyUpdateReason::kLocalForTests));
         } else {
           ADD_FAILURE() << "Missing server connection";
         }
@@ -4904,7 +4907,8 @@
           if (!server_connection->IsKeyUpdateAllowed()) {
             return false;
           }
-          EXPECT_TRUE(server_connection->InitiateKeyUpdate());
+          EXPECT_TRUE(server_connection->InitiateKeyUpdate(
+              KeyUpdateReason::kLocalForTests));
         } else {
           ADD_FAILURE() << "Missing server connection";
         }
@@ -4956,7 +4960,8 @@
             // key phase, wait a bit and try again.
             return false;
           }
-          EXPECT_TRUE(server_connection->InitiateKeyUpdate());
+          EXPECT_TRUE(server_connection->InitiateKeyUpdate(
+              KeyUpdateReason::kLocalForTests));
         } else {
           ADD_FAILURE() << "Missing server connection";
         }
@@ -4965,7 +4970,8 @@
       QuicTime::Delta::FromSeconds(5));
   QuicConnection* client_connection = GetClientConnection();
   ASSERT_TRUE(client_connection);
-  EXPECT_TRUE(client_connection->InitiateKeyUpdate());
+  EXPECT_TRUE(
+      client_connection->InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
 
   SendSynchronousFooRequestAndCheckResponse();
   EXPECT_EQ(1u, client_connection->GetStats().key_update_count);
@@ -4980,14 +4986,16 @@
           if (!server_connection->IsKeyUpdateAllowed()) {
             return false;
           }
-          EXPECT_TRUE(server_connection->InitiateKeyUpdate());
+          EXPECT_TRUE(server_connection->InitiateKeyUpdate(
+              KeyUpdateReason::kLocalForTests));
         } else {
           ADD_FAILURE() << "Missing server connection";
         }
         return true;
       },
       QuicTime::Delta::FromSeconds(5));
-  EXPECT_TRUE(client_connection->InitiateKeyUpdate());
+  EXPECT_TRUE(
+      client_connection->InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
 
   SendSynchronousFooRequestAndCheckResponse();
   EXPECT_EQ(2u, client_connection->GetStats().key_update_count);
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index e9fd55e..0aa7a4d 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -1932,9 +1932,9 @@
                                ConnectionCloseSource::FROM_PEER);
 }
 
-void QuicConnection::OnKeyUpdate() {
+void QuicConnection::OnKeyUpdate(KeyUpdateReason reason) {
   DCHECK(support_key_update_for_connection_);
-  QUIC_DLOG(INFO) << ENDPOINT << "Key phase updated";
+  QUIC_DLOG(INFO) << ENDPOINT << "Key phase updated for " << reason;
 
   lowest_packet_sent_in_current_key_phase_.Clear();
   stats_.key_update_count++;
@@ -3189,6 +3189,7 @@
     // Approaching the confidentiality limit, initiate key update so that
     // the next set of keys will be ready for the next packet before the
     // limit is reached.
+    KeyUpdateReason reason = KeyUpdateReason::kLocalAeadConfidentialityLimit;
     if (key_update_limit_override) {
       QUIC_DLOG(INFO) << ENDPOINT
                       << "reached FLAGS_quic_key_update_confidentiality_limit, "
@@ -3197,6 +3198,7 @@
                       << num_packets_encrypted_in_current_key_phase
                       << " key_update_limit=" << key_update_limit
                       << " confidentiality_limit=" << confidentiality_limit;
+      reason = KeyUpdateReason::kLocalKeyUpdateLimitOverride;
     } else {
       QUIC_DLOG(INFO) << ENDPOINT
                       << "approaching AEAD confidentiality limit, "
@@ -3206,7 +3208,7 @@
                       << " key_update_limit=" << key_update_limit
                       << " confidentiality_limit=" << confidentiality_limit;
     }
-    InitiateKeyUpdate();
+    InitiateKeyUpdate(reason);
   }
 
   return false;
@@ -3683,13 +3685,13 @@
          GetLargestAckedPacket() >= lowest_packet_sent_in_current_key_phase_;
 }
 
-bool QuicConnection::InitiateKeyUpdate() {
+bool QuicConnection::InitiateKeyUpdate(KeyUpdateReason reason) {
   QUIC_DLOG(INFO) << ENDPOINT << "InitiateKeyUpdate";
   if (!IsKeyUpdateAllowed()) {
     QUIC_BUG << "key update not allowed";
     return false;
   }
-  return framer_.DoKeyUpdate();
+  return framer_.DoKeyUpdate(reason);
 }
 
 const QuicDecrypter* QuicConnection::decrypter() const {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 2932584..2fc8c8a 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -646,7 +646,7 @@
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
       const QuicIetfStatelessResetPacket& packet) override;
-  void OnKeyUpdate() override;
+  void OnKeyUpdate(KeyUpdateReason reason) override;
   void OnDecryptedFirstPacketInKeyPhase() override;
   std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
       override;
@@ -819,7 +819,7 @@
 
   // Increment the key phase. It is a bug to call this when IsKeyUpdateAllowed()
   // is false. Returns false on error.
-  bool InitiateKeyUpdate();
+  bool InitiateKeyUpdate(KeyUpdateReason reason);
 
   const QuicDecrypter* decrypter() const;
   const QuicDecrypter* alternative_decrypter() const;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 42d19e2..483ddb1 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -12096,7 +12096,7 @@
   EXPECT_CALL(visitor_, CreateCurrentOneRttEncrypter()).WillOnce([]() {
     return std::make_unique<TaggingEncrypter>(0x02);
   });
-  EXPECT_TRUE(connection_.InitiateKeyUpdate());
+  EXPECT_TRUE(connection_.InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
   // discard_previous_keys_alarm_ should not be set until a packet from the new
   // key phase has been received. (The alarm that was set above should be
   // cleared if it hasn't fired before the next key update happened.)
@@ -12110,7 +12110,7 @@
   EXPECT_CALL(peer_framer_visitor_, CreateCurrentOneRttEncrypter())
       .WillOnce([]() { return std::make_unique<TaggingEncrypter>(0x02); });
   peer_framer_.SetKeyUpdateSupportForConnection(true);
-  peer_framer_.DoKeyUpdate();
+  peer_framer_.DoKeyUpdate(KeyUpdateReason::kRemote);
 
   // Another key update should not be allowed yet.
   EXPECT_FALSE(connection_.IsKeyUpdateAllowed());
@@ -12132,7 +12132,7 @@
   EXPECT_CALL(visitor_, CreateCurrentOneRttEncrypter()).WillOnce([]() {
     return std::make_unique<TaggingEncrypter>(0x03);
   });
-  EXPECT_TRUE(connection_.InitiateKeyUpdate());
+  EXPECT_TRUE(connection_.InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
 
   // Pretend that peer accepts the key update.
   EXPECT_CALL(peer_framer_visitor_,
@@ -12141,7 +12141,7 @@
           []() { return std::make_unique<StrictTaggingDecrypter>(0x03); });
   EXPECT_CALL(peer_framer_visitor_, CreateCurrentOneRttEncrypter())
       .WillOnce([]() { return std::make_unique<TaggingEncrypter>(0x03); });
-  peer_framer_.DoKeyUpdate();
+  peer_framer_.DoKeyUpdate(KeyUpdateReason::kRemote);
 
   // Another key update should not be allowed yet.
   EXPECT_FALSE(connection_.IsKeyUpdateAllowed());
@@ -12166,7 +12166,7 @@
   EXPECT_CALL(visitor_, CreateCurrentOneRttEncrypter()).WillOnce([]() {
     return std::make_unique<TaggingEncrypter>(0x04);
   });
-  EXPECT_TRUE(connection_.InitiateKeyUpdate());
+  EXPECT_TRUE(connection_.InitiateKeyUpdate(KeyUpdateReason::kLocalForTests));
   EXPECT_FALSE(connection_.GetDiscardPreviousOneRttKeysAlarm()->IsSet());
 }
 
@@ -12254,7 +12254,7 @@
           .WillOnce([current_tag]() {
             return std::make_unique<TaggingEncrypter>(current_tag);
           });
-      peer_framer_.DoKeyUpdate();
+      peer_framer_.DoKeyUpdate(KeyUpdateReason::kRemote);
     }
     // Receive ack for packet.
     EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index f775afb..a5cc8bd 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -4255,7 +4255,7 @@
   previous_decrypter_ = nullptr;
 }
 
-bool QuicFramer::DoKeyUpdate() {
+bool QuicFramer::DoKeyUpdate(KeyUpdateReason reason) {
   DCHECK(support_key_update_for_connection_);
   if (!next_decrypter_) {
     // If key update is locally initiated, next decrypter might not be created
@@ -4275,7 +4275,7 @@
   previous_decrypter_ = std::move(decrypter_[ENCRYPTION_FORWARD_SECURE]);
   decrypter_[ENCRYPTION_FORWARD_SECURE] = std::move(next_decrypter_);
   encrypter_[ENCRYPTION_FORWARD_SECURE] = std::move(next_encrypter);
-  visitor_->OnKeyUpdate();
+  visitor_->OnKeyUpdate(reason);
   return true;
 }
 
@@ -4750,7 +4750,7 @@
     visitor_->OnDecryptedPacket(level);
     *decrypted_level = level;
     if (attempt_key_update) {
-      if (!DoKeyUpdate()) {
+      if (!DoKeyUpdate(KeyUpdateReason::kRemote)) {
         set_detailed_error("Key update failed due to internal error");
         return RaiseError(QUIC_INTERNAL_ERROR);
       }
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h
index f029dd1..5d9bf46 100644
--- a/quic/core/quic_framer.h
+++ b/quic/core/quic_framer.h
@@ -241,7 +241,7 @@
   // Called when a Key Phase Update has been initiated. This is called for both
   // locally and peer initiated key updates. If the key update was locally
   // initiated, this does not indicate the peer has received the key update yet.
-  virtual void OnKeyUpdate() = 0;
+  virtual void OnKeyUpdate(KeyUpdateReason reason) = 0;
 
   // Called on the first decrypted packet in each key phase (including the
   // first key phase.)
@@ -546,7 +546,7 @@
   // Discard the decrypter for the previous key phase.
   void DiscardPreviousOneRttKeys();
   // Update the key phase.
-  bool DoKeyUpdate();
+  bool DoKeyUpdate(KeyUpdateReason reason);
 
   const QuicDecrypter* GetDecrypter(EncryptionLevel level) const;
   const QuicDecrypter* decrypter() const;
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index e21b2ef..949d246 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -221,7 +221,6 @@
         packet_count_(0),
         frame_count_(0),
         complete_packets_(0),
-        key_update_count_(0),
         derive_next_key_count_(0),
         decrypted_first_packet_in_key_phase_count_(0),
         accept_packet_(true),
@@ -578,7 +577,9 @@
     EXPECT_EQ(0u, framer_->current_received_frame_type());
   }
 
-  void OnKeyUpdate() override { key_update_count_++; }
+  void OnKeyUpdate(KeyUpdateReason reason) override {
+    key_update_reasons_.push_back(reason);
+  }
 
   void OnDecryptedFirstPacketInKeyPhase() override {
     decrypted_first_packet_in_key_phase_count_++;
@@ -598,13 +599,15 @@
     transport_version_ = framer->transport_version();
   }
 
+  size_t key_update_count() const { return key_update_reasons_.size(); }
+
   // Counters from the visitor_ callbacks.
   int error_count_;
   int version_mismatch_;
   int packet_count_;
   int frame_count_;
   int complete_packets_;
-  int key_update_count_;
+  std::vector<KeyUpdateReason> key_update_reasons_;
   int derive_next_key_count_;
   int decrypted_first_packet_in_key_phase_count_;
   bool accept_packet_;
@@ -14838,7 +14841,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
   // Processed valid packet with phase=0, key=1: no key update.
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(0, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -14852,7 +14855,8 @@
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
   // Processed valid packet with phase=1, key=2: key update should have
   // occurred.
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  ASSERT_EQ(1u, visitor_.key_update_count());
+  EXPECT_EQ(KeyUpdateReason::kRemote, visitor_.key_update_reasons_[0]);
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -14865,7 +14869,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
   // Processed another valid packet with phase=1, key=2: no key update.
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -14878,7 +14882,8 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(2, visitor_.key_update_count_);
+  ASSERT_EQ(2u, visitor_.key_update_count());
+  EXPECT_EQ(KeyUpdateReason::kRemote, visitor_.key_update_reasons_[1]);
   EXPECT_EQ(2, visitor_.derive_next_key_count_);
   EXPECT_EQ(3, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -14912,7 +14917,7 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(0, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -14925,7 +14930,7 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -14940,7 +14945,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   // Packet should decrypt and key update count should not change.
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -14974,7 +14979,7 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(0, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -14987,7 +14992,7 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15005,7 +15010,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   // Packet should not decrypt and key update count should not change.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -15039,7 +15044,7 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(0, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15052,7 +15057,7 @@
   ASSERT_TRUE(encrypted);
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15067,7 +15072,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   // Packet should decrypt and key update count should not change.
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(2, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -15102,7 +15107,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
   // Processed valid packet with phase=0, key=1: no key update.
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(0, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15117,7 +15122,7 @@
   // update, but next decrypter key should have been created to attempt to
   // decode it.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15131,7 +15136,7 @@
   // Packet with phase=1 but key=1, should not process and should not cause key
   // update.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15145,7 +15150,7 @@
   // Packet with phase=0 but key=2, should not process and should not cause key
   // update.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -15181,7 +15186,7 @@
   // update enabled (SetNextOneRttCrypters never called). Should fail to
   // process.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(0, visitor_.key_update_count_);
+  EXPECT_EQ(0u, visitor_.key_update_count());
   EXPECT_EQ(0, visitor_.derive_next_key_count_);
   EXPECT_EQ(0, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -15198,10 +15203,11 @@
                            std::make_unique<StrictTaggingDecrypter>(/*key=*/0));
   framer_.SetKeyUpdateSupportForConnection(true);
 
-  EXPECT_TRUE(framer_.DoKeyUpdate());
+  EXPECT_TRUE(framer_.DoKeyUpdate(KeyUpdateReason::kLocalForTests));
   // Key update count should be updated, but haven't received packet from peer
   // with new key phase.
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  ASSERT_EQ(1u, visitor_.key_update_count());
+  EXPECT_EQ(KeyUpdateReason::kLocalForTests, visitor_.key_update_reasons_[0]);
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(0, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15225,7 +15231,7 @@
   // Packet should decrypt and key update count should not change and
   // OnDecryptedFirstPacketInKeyPhase should have been called.
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15240,7 +15246,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   // Packet should decrypt and key update count should not change.
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15256,7 +15262,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   // Packet should not decrypt and key update count should not change.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(2, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
@@ -15273,10 +15279,10 @@
                            std::make_unique<StrictTaggingDecrypter>(/*key=*/0));
   framer_.SetKeyUpdateSupportForConnection(true);
 
-  EXPECT_TRUE(framer_.DoKeyUpdate());
+  EXPECT_TRUE(framer_.DoKeyUpdate(KeyUpdateReason::kLocalForTests));
   // Key update count should be updated, but haven't received packet
   // from peer with new key phase.
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(0, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15302,7 +15308,7 @@
   // OnDecryptedFirstPacketInKeyPhase should not have been called since the
   // packet was from the previous key phase.
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(0, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15317,7 +15323,7 @@
   // Packet should decrypt and key update count should not change, but
   // OnDecryptedFirstPacketInKeyPhase should have been called.
   EXPECT_TRUE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(1, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 
@@ -15333,7 +15339,7 @@
   QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
   // Packet should not decrypt and key update count should not change.
   EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
-  EXPECT_EQ(1, visitor_.key_update_count_);
+  EXPECT_EQ(1u, visitor_.key_update_count());
   EXPECT_EQ(2, visitor_.derive_next_key_count_);
   EXPECT_EQ(1, visitor_.decrypted_first_packet_in_key_phase_count_);
 }
diff --git a/quic/core/quic_types.cc b/quic/core/quic_types.cc
index 4027ffa..9eb0a27 100644
--- a/quic/core/quic_types.cc
+++ b/quic/core/quic_types.cc
@@ -363,6 +363,29 @@
   return os;
 }
 
+std::string KeyUpdateReasonString(KeyUpdateReason reason) {
+#define RETURN_REASON_LITERAL(x) \
+  case KeyUpdateReason::x:       \
+    return #x
+  switch (reason) {
+    RETURN_REASON_LITERAL(kInvalid);
+    RETURN_REASON_LITERAL(kRemote);
+    RETURN_REASON_LITERAL(kLocalForTests);
+    RETURN_REASON_LITERAL(kLocalForInteropRunner);
+    RETURN_REASON_LITERAL(kLocalAeadConfidentialityLimit);
+    RETURN_REASON_LITERAL(kLocalKeyUpdateLimitOverride);
+    default:
+      return quiche::QuicheStrCat("Unknown(", static_cast<int>(reason), ")");
+      break;
+  }
+#undef RETURN_REASON_LITERAL
+}
+
+std::ostream& operator<<(std::ostream& os, const KeyUpdateReason reason) {
+  os << KeyUpdateReasonString(reason);
+  return os;
+}
+
 #undef RETURN_STRING_LITERAL  // undef for jumbo builds
 
 }  // namespace quic
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index 4a896a0..514c91f 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -798,6 +798,21 @@
   }
 };
 
+// These values must remain stable as they are uploaded to UMA histograms.
+enum class KeyUpdateReason {
+  kInvalid = 0,
+  kRemote = 1,
+  kLocalForTests = 2,
+  kLocalForInteropRunner = 3,
+  kLocalAeadConfidentialityLimit = 4,
+  kLocalKeyUpdateLimitOverride = 5,
+};
+
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+                                             const KeyUpdateReason reason);
+
+QUIC_EXPORT_PRIVATE std::string KeyUpdateReasonString(KeyUpdateReason reason);
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_QUIC_TYPES_H_
diff --git a/quic/core/tls_chlo_extractor.h b/quic/core/tls_chlo_extractor.h
index 6d2f254..718e5fa 100644
--- a/quic/core/tls_chlo_extractor.h
+++ b/quic/core/tls_chlo_extractor.h
@@ -160,7 +160,7 @@
   }
   void OnAuthenticatedIetfStatelessResetPacket(
       const QuicIetfStatelessResetPacket& /*packet*/) override {}
-  void OnKeyUpdate() override {}
+  void OnKeyUpdate(KeyUpdateReason /*reason*/) override {}
   void OnDecryptedFirstPacketInKeyPhase() override {}
   std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
       override {
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index a46a11b..e577174 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -424,7 +424,7 @@
               OnAuthenticatedIetfStatelessResetPacket,
               (const QuicIetfStatelessResetPacket&),
               (override));
-  MOCK_METHOD(void, OnKeyUpdate, (), (override));
+  MOCK_METHOD(void, OnKeyUpdate, (KeyUpdateReason), (override));
   MOCK_METHOD(void, OnDecryptedFirstPacketInKeyPhase, (), (override));
   MOCK_METHOD(std::unique_ptr<QuicDecrypter>,
               AdvanceKeysAndCreateCurrentOneRttDecrypter,
@@ -493,7 +493,7 @@
   bool IsValidStatelessResetToken(QuicUint128 token) const override;
   void OnAuthenticatedIetfStatelessResetPacket(
       const QuicIetfStatelessResetPacket& /*packet*/) override {}
-  void OnKeyUpdate() override {}
+  void OnKeyUpdate(KeyUpdateReason /*reason*/) override {}
   void OnDecryptedFirstPacketInKeyPhase() override {}
   std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
       override {
diff --git a/quic/test_tools/simple_quic_framer.cc b/quic/test_tools/simple_quic_framer.cc
index 4a77331..ccce52b 100644
--- a/quic/test_tools/simple_quic_framer.cc
+++ b/quic/test_tools/simple_quic_framer.cc
@@ -220,7 +220,7 @@
         std::make_unique<QuicIetfStatelessResetPacket>(packet);
   }
 
-  void OnKeyUpdate() override {}
+  void OnKeyUpdate(KeyUpdateReason /*reason*/) override {}
   void OnDecryptedFirstPacketInKeyPhase() override {}
   std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
       override {
diff --git a/quic/tools/quic_client_interop_test_bin.cc b/quic/tools/quic_client_interop_test_bin.cc
index 15871d8..6f9f685 100644
--- a/quic/tools/quic_client_interop_test_bin.cc
+++ b/quic/tools/quic_client_interop_test_bin.cc
@@ -299,7 +299,8 @@
 
     if (attempt_key_update) {
       if (connection->IsKeyUpdateAllowed()) {
-        if (connection->InitiateKeyUpdate()) {
+        if (connection->InitiateKeyUpdate(
+                KeyUpdateReason::kLocalForInteropRunner)) {
           client->SendRequestAndWaitForResponse(header_block, "", /*fin=*/true);
           if (!client->connected()) {
             // Key update does not work, retry without attempting it.
diff --git a/quic/tools/quic_packet_printer_bin.cc b/quic/tools/quic_packet_printer_bin.cc
index e64e1ac..6f9a658 100644
--- a/quic/tools/quic_packet_printer_bin.cc
+++ b/quic/tools/quic_packet_printer_bin.cc
@@ -220,7 +220,9 @@
       const QuicIetfStatelessResetPacket& /*packet*/) override {
     std::cerr << "OnAuthenticatedIetfStatelessResetPacket\n";
   }
-  void OnKeyUpdate() override { std::cerr << "OnKeyUpdate\n"; }
+  void OnKeyUpdate(KeyUpdateReason reason) override {
+    std::cerr << "OnKeyUpdate: " << reason << "\n";
+  }
   void OnDecryptedFirstPacketInKeyPhase() override {
     std::cerr << "OnDecryptedFirstPacketInKeyPhase\n";
   }