Matter SDK Coverage Report
Current view: top level - app - ReadHandler.cpp (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 83.1 % 421 350
Test Date: 2026-06-03 07:35:21 Functions: 87.9 % 33 29

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : #include <app/AppConfig.h>
      19              : #include <app/AttributePathExpandIterator.h>
      20              : #include <app/InteractionModelEngine.h>
      21              : #include <app/MessageDef/EventPathIB.h>
      22              : #include <app/MessageDef/StatusResponseMessage.h>
      23              : #include <app/MessageDef/SubscribeRequestMessage.h>
      24              : #include <app/MessageDef/SubscribeResponseMessage.h>
      25              : #include <app/data-model-provider/Provider.h>
      26              : #include <app/icd/server/ICDServerConfig.h>
      27              : #include <lib/core/TLVUtilities.h>
      28              : #include <lib/support/CodeUtils.h>
      29              : #include <messaging/ExchangeContext.h>
      30              : 
      31              : #include <app/ReadHandler.h>
      32              : #include <app/reporting/Engine.h>
      33              : 
      34              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      35              : #include <app/icd/server/ICDConfigurationData.h> //nogncheck
      36              : #endif
      37              : 
      38              : namespace chip {
      39              : namespace app {
      40              : using Status = Protocols::InteractionModel::Status;
      41              : 
      42           33 : uint16_t ReadHandler::GetPublisherSelectedIntervalLimit()
      43              : {
      44              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
      45              :     // We don't need to check for precision loss since the max value of the IdleModeDuration can fit inside a uint16_t
      46              :     const auto idleModeDuration =
      47              :         std::chrono::duration_cast<System::Clock::Seconds16>(ICDConfigurationData::GetInstance().GetIdleModeDuration()).count();
      48              :     return std::max(idleModeDuration, kSubscriptionMaxIntervalPublisherLimit);
      49              : #else
      50           33 :     return kSubscriptionMaxIntervalPublisherLimit;
      51              : #endif
      52              : }
      53              : 
      54         1138 : ReadHandler::ReadHandler(ManagementCallback & apCallback, Messaging::ExchangeContext * apExchangeContext,
      55         1138 :                          InteractionType aInteractionType, Observer * observer) :
      56         1138 :     mExchangeCtx(*this),
      57         2276 :     mManagementCallback(apCallback)
      58              : {
      59         1138 :     VerifyOrDie(apExchangeContext != nullptr);
      60              : 
      61         1138 :     mExchangeCtx.Grab(apExchangeContext);
      62              : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
      63              :     // TODO: this should be replaced by a pointer to the InteractionModelEngine that created the ReadHandler
      64              :     // once InteractionModelEngine is no longer a singleton (see issue 23625)
      65              :     mExchangeMgr = apExchangeContext->GetExchangeMgr();
      66              : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
      67              : 
      68         1138 :     mInteractionType            = aInteractionType;
      69         1138 :     mLastWrittenEventsBytes     = 0;
      70         1138 :     mTransactionStartGeneration = mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
      71         1138 :     mFlags.ClearAll();
      72         1138 :     SetStateFlag(ReadHandlerFlags::PrimingReports);
      73              : 
      74         1138 :     mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
      75              : 
      76         1138 :     VerifyOrDie(observer != nullptr);
      77         1138 :     mObserver = observer;
      78         1138 : }
      79              : 
      80              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
      81            0 : ReadHandler::ReadHandler(ManagementCallback & apCallback, Observer * observer) :
      82            0 :     mExchangeCtx(*this), mManagementCallback(apCallback)
      83              : {
      84            0 :     mInteractionType = InteractionType::Subscribe;
      85            0 :     mFlags.ClearAll();
      86              : 
      87            0 :     VerifyOrDie(observer != nullptr);
      88            0 :     mObserver = observer;
      89            0 : }
      90              : 
      91            0 : void ReadHandler::OnSubscriptionResumed(const SessionHandle & sessionHandle,
      92              :                                         SubscriptionResumptionSessionEstablisher & resumptionSessionEstablisher)
      93              : {
      94            0 :     mSubscriptionId          = resumptionSessionEstablisher.mSubscriptionInfo.mSubscriptionId;
      95            0 :     mMinIntervalFloorSeconds = resumptionSessionEstablisher.mSubscriptionInfo.mMinInterval;
      96            0 :     mMaxInterval             = resumptionSessionEstablisher.mSubscriptionInfo.mMaxInterval;
      97            0 :     SetStateFlag(ReadHandlerFlags::FabricFiltered, resumptionSessionEstablisher.mSubscriptionInfo.mFabricFiltered);
      98              : 
      99              :     // Move dynamically allocated attributes and events from the SubscriptionInfo struct into
     100              :     // the object pool managed by the IM engine
     101            0 :     for (size_t i = 0; i < resumptionSessionEstablisher.mSubscriptionInfo.mAttributePaths.AllocatedSize(); i++)
     102              :     {
     103            0 :         AttributePathParams params = resumptionSessionEstablisher.mSubscriptionInfo.mAttributePaths[i].GetParams();
     104            0 :         CHIP_ERROR err = mManagementCallback.GetInteractionModelEngine()->PushFrontAttributePathList(mpAttributePathList, params);
     105            0 :         if (err != CHIP_NO_ERROR)
     106              :         {
     107            0 :             Close();
     108            0 :             return;
     109              :         }
     110              :     }
     111            0 :     for (size_t i = 0; i < resumptionSessionEstablisher.mSubscriptionInfo.mEventPaths.AllocatedSize(); i++)
     112              :     {
     113            0 :         EventPathParams params = resumptionSessionEstablisher.mSubscriptionInfo.mEventPaths[i].GetParams();
     114            0 :         CHIP_ERROR err = mManagementCallback.GetInteractionModelEngine()->PushFrontEventPathParamsList(mpEventPathList, params);
     115            0 :         if (err != CHIP_NO_ERROR)
     116              :         {
     117            0 :             Close();
     118            0 :             return;
     119              :         }
     120              :     }
     121              : 
     122            0 :     mSessionHandle.Grab(sessionHandle);
     123              : 
     124            0 :     SetStateFlag(ReadHandlerFlags::ActiveSubscription);
     125              : 
     126            0 :     auto * appCallback = mManagementCallback.GetAppCallback();
     127            0 :     if (appCallback)
     128              :     {
     129            0 :         appCallback->OnSubscriptionEstablished(*this);
     130              :     }
     131              :     // Notify the observer that a subscription has been resumed
     132            0 :     mObserver->OnSubscriptionEstablished(this);
     133              : 
     134            0 :     MoveToState(HandlerState::CanStartReporting);
     135              : 
     136            0 :     SingleLinkedListNode<AttributePathParams> * attributePath = mpAttributePathList;
     137            0 :     while (attributePath)
     138              :     {
     139            0 :         TEMPORARY_RETURN_IGNORED mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().SetDirty(
     140            0 :             attributePath->mValue);
     141            0 :         attributePath = attributePath->mpNext;
     142              :     }
     143              : }
     144              : 
     145              : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     146              : 
     147         1138 : ReadHandler::~ReadHandler()
     148              : {
     149         1138 :     mObserver->OnReadHandlerDestroyed(this);
     150              : 
     151         1138 :     auto * appCallback = mManagementCallback.GetAppCallback();
     152         1138 :     if (mFlags.Has(ReadHandlerFlags::ActiveSubscription) && appCallback)
     153              :     {
     154          240 :         mFlags.Clear(ReadHandlerFlags::ActiveSubscription);
     155          240 :         appCallback->OnSubscriptionTerminated(*this);
     156              :     }
     157              : 
     158         1138 :     if (IsAwaitingReportResponse())
     159              :     {
     160            2 :         mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
     161              :     }
     162         1138 :     mManagementCallback.GetInteractionModelEngine()->ReleaseAttributePathList(mpAttributePathList);
     163         1138 :     mManagementCallback.GetInteractionModelEngine()->ReleaseEventPathList(mpEventPathList);
     164         1138 :     mManagementCallback.GetInteractionModelEngine()->ReleaseDataVersionFilterList(mpDataVersionFilterList);
     165         1138 : }
     166              : 
     167          868 : void ReadHandler::Close(CloseOptions options)
     168              : {
     169              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     170          868 :     if (IsType(InteractionType::Subscribe) && options == CloseOptions::kDropPersistedSubscription)
     171              :     {
     172          102 :         auto * subscriptionResumptionStorage = mManagementCallback.GetInteractionModelEngine()->GetSubscriptionResumptionStorage();
     173          102 :         if (subscriptionResumptionStorage)
     174              :         {
     175            0 :             TEMPORARY_RETURN_IGNORED subscriptionResumptionStorage->Delete(GetInitiatorNodeId(), GetAccessingFabricIndex(),
     176              :                                                                            mSubscriptionId);
     177              :         }
     178              :     }
     179              : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     180              : 
     181              : #if CHIP_PROGRESS_LOGGING
     182          868 :     if (IsType(InteractionType::Subscribe))
     183              :     {
     184          116 :         const ScopedNodeId & peer = mSessionHandle ? mSessionHandle->GetPeer() : ScopedNodeId();
     185          116 :         ChipLogProgress(DataManagement, "Subscription id 0x%" PRIx32 " from node " ChipLogFormatScopedNodeId " torn down",
     186              :                         mSubscriptionId, ChipLogValueScopedNodeId(peer));
     187              :     }
     188              : #endif // CHIP_PROGRESS_LOGGING
     189              : 
     190          868 :     MoveToState(HandlerState::AwaitingDestruction);
     191          868 :     mManagementCallback.OnDone(*this);
     192          868 : }
     193              : 
     194         1090 : void ReadHandler::OnInitialRequest(System::PacketBufferHandle && aPayload)
     195              : {
     196         1090 :     CHIP_ERROR err = CHIP_NO_ERROR;
     197         1090 :     System::PacketBufferHandle response;
     198              : 
     199         1090 :     if (IsType(InteractionType::Subscribe))
     200              :     {
     201          303 :         err = ProcessSubscribeRequest(std::move(aPayload));
     202              :     }
     203              :     else
     204              :     {
     205          787 :         err = ProcessReadRequest(std::move(aPayload));
     206              :     }
     207              : 
     208         2180 :     if (err != CHIP_NO_ERROR)
     209              :     {
     210            8 :         Status status = Status::InvalidAction;
     211            8 :         if (err.IsIMStatus())
     212              :         {
     213            0 :             status = StatusIB(err).mStatus;
     214              :         }
     215            8 :         TEMPORARY_RETURN_IGNORED StatusResponse::Send(status, mExchangeCtx.Get(), /* aExpectResponse = */ false);
     216              :         // At this point we can't have a persisted subscription, since that
     217              :         // happens only when ProcessSubscribeRequest returns success. And our
     218              :         // subscription id is almost certainly not actually useful at this
     219              :         // point, either.  So don't try to mess with persisted subscriptions in
     220              :         // Close().
     221            8 :         Close(CloseOptions::kKeepPersistedSubscription);
     222              :     }
     223              :     else
     224              :     {
     225              :         // Force us to be in a dirty state so we get processed by the reporting
     226         1082 :         SetStateFlag(ReadHandlerFlags::ForceDirty);
     227              :     }
     228         1090 : }
     229              : 
     230         1231 : CHIP_ERROR ReadHandler::OnStatusResponse(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload,
     231              :                                          bool & aSendStatusResponse)
     232              : {
     233         1231 :     CHIP_ERROR err         = CHIP_NO_ERROR;
     234         1231 :     aSendStatusResponse    = true;
     235         1231 :     CHIP_ERROR statusError = CHIP_NO_ERROR;
     236         1231 :     SuccessOrExit(err = StatusResponse::ProcessStatusResponse(std::move(aPayload), statusError));
     237              :     // Since this is a valid Status Response message, we don't have to send a Status Response in reply to it.
     238         1229 :     aSendStatusResponse = false;
     239         1229 :     SuccessOrExit(err = statusError);
     240         1217 :     switch (mState)
     241              :     {
     242         1217 :     case HandlerState::AwaitingReportResponse:
     243         1217 :         if (IsChunkedReport())
     244              :         {
     245          856 :             mExchangeCtx->WillSendMessage();
     246              :         }
     247          361 :         else if (IsType(InteractionType::Subscribe))
     248              :         {
     249          361 :             if (IsPriming())
     250              :             {
     251          284 :                 err = SendSubscribeResponse();
     252              : 
     253          284 :                 SetStateFlag(ReadHandlerFlags::ActiveSubscription);
     254          284 :                 auto * appCallback = mManagementCallback.GetAppCallback();
     255          284 :                 if (appCallback)
     256              :                 {
     257          240 :                     appCallback->OnSubscriptionEstablished(*this);
     258              :                 }
     259          284 :                 mObserver->OnSubscriptionEstablished(this);
     260              :             }
     261              :         }
     262              :         else
     263              :         {
     264              :             //
     265              :             // We're done processing a read, so let's close out and return.
     266              :             //
     267            0 :             Close();
     268            0 :             return CHIP_NO_ERROR;
     269              :         }
     270              : 
     271         1217 :         MoveToState(HandlerState::CanStartReporting);
     272         1217 :         break;
     273              : 
     274            0 :     case HandlerState::CanStartReporting:
     275              :     case HandlerState::Idle:
     276              :     default:
     277            0 :         err = CHIP_ERROR_INCORRECT_STATE;
     278            0 :         break;
     279              :     }
     280              : 
     281         1231 : exit:
     282         1231 :     return err;
     283              : }
     284              : 
     285         1982 : CHIP_ERROR ReadHandler::AcquireExchangeForSend()
     286              : {
     287         1982 :     if (IsPriming() || IsChunkedReport())
     288              :     {
     289              :         // We already hold mExchangeCtx from the inbound request. The underlying
     290              :         // session can be released while a send is pending (e.g. TCP teardown);
     291              :         // guard before grabbing it to avoid crashing in UseSuggestedResponseTimeout.
     292         1896 :         VerifyOrReturnLogError(mExchangeCtx->HasSessionHandle(), CHIP_ERROR_MISSING_SECURE_SESSION);
     293         1894 :         mSessionHandle.Grab(mExchangeCtx->GetSessionHandle());
     294              :     }
     295              :     else
     296              :     {
     297              :         // For subscription re-reports, the previous exchange was released after
     298              :         // the last send. mExchangeCtx must be null here; open a fresh exchange
     299              :         // from the stored session handle.
     300           86 :         VerifyOrReturnLogError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     301           86 :         VerifyOrReturnLogError(mSessionHandle, CHIP_ERROR_INCORRECT_STATE);
     302              : #if CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     303              :         auto exchange = mExchangeMgr->NewContext(mSessionHandle.Get().Value(), this);
     304              : #else  // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     305              :         auto exchange =
     306           86 :             mManagementCallback.GetInteractionModelEngine()->GetExchangeManager()->NewContext(mSessionHandle.Get().Value(), this);
     307              : #endif // CHIP_CONFIG_UNSAFE_SUBSCRIPTION_EXCHANGE_MANAGER_USE
     308           86 :         VerifyOrReturnLogError(exchange != nullptr, CHIP_ERROR_INCORRECT_STATE);
     309           84 :         mExchangeCtx.Grab(exchange);
     310              :     }
     311         1978 :     return CHIP_NO_ERROR;
     312              : }
     313              : 
     314           32 : CHIP_ERROR ReadHandler::SendStatusReport(Protocols::InteractionModel::Status aStatus)
     315              : {
     316           32 :     VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
     317           32 :     ReturnErrorOnFailure(AcquireExchangeForSend());
     318           31 :     return StatusResponse::Send(aStatus, mExchangeCtx.Get(), /* aExpectResponse = */ false);
     319              : }
     320              : 
     321         1954 : CHIP_ERROR ReadHandler::SendReportData(System::PacketBufferHandle && aPayload, bool aMoreChunks)
     322              : {
     323         1954 :     VerifyOrReturnLogError(mState == HandlerState::CanStartReporting, CHIP_ERROR_INCORRECT_STATE);
     324         1950 :     VerifyOrDie(!IsAwaitingReportResponse()); // Should not be reportable!
     325         1950 :     ReturnErrorOnFailure(AcquireExchangeForSend());
     326              : 
     327         1947 :     if (!IsReporting())
     328              :     {
     329              :         mCurrentReportsBeginGeneration =
     330         1135 :             mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
     331              :     }
     332         1947 :     SetStateFlag(ReadHandlerFlags::ChunkedReport, aMoreChunks);
     333         1947 :     bool responseExpected = IsType(InteractionType::Subscribe) || aMoreChunks;
     334              : 
     335         1947 :     ReturnErrorOnFailure(mExchangeCtx->UseSuggestedResponseTimeout(app::kExpectedIMProcessingTime));
     336         1947 :     CHIP_ERROR err = mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReportData, std::move(aPayload),
     337              :                                                responseExpected ? Messaging::SendMessageFlags::kExpectResponse
     338              :                                                                 : Messaging::SendMessageFlags::kNone);
     339         3894 :     if (err == CHIP_NO_ERROR)
     340              :     {
     341         1945 :         if (responseExpected)
     342              :         {
     343         1241 :             MoveToState(HandlerState::AwaitingReportResponse);
     344              :         }
     345              :         else
     346              :         {
     347              :             // Make sure we're not treated as an in-flight report waiting for a
     348              :             // response by the reporting engine.
     349          704 :             mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
     350              :         }
     351              : 
     352              :         // If we just finished a non-priming subscription report, notify our observers.
     353              :         // Priming reports are handled when we send a SubscribeResponse.
     354         1945 :         if (IsType(InteractionType::Subscribe) && !IsPriming() && !IsChunkedReport())
     355              :         {
     356           82 :             mObserver->OnSubscriptionReportSent(this);
     357              :         }
     358              :     }
     359         1947 :     if (!aMoreChunks)
     360              :     {
     361         1081 :         mPreviousReportsBeginGeneration = mCurrentReportsBeginGeneration;
     362         1081 :         ClearForceDirtyFlag();
     363         1081 :         mManagementCallback.GetInteractionModelEngine()->ReleaseDataVersionFilterList(mpDataVersionFilterList);
     364              :     }
     365              : 
     366         1947 :     return err;
     367              : }
     368              : 
     369         1233 : CHIP_ERROR ReadHandler::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
     370              :                                           System::PacketBufferHandle && aPayload)
     371              : {
     372         1233 :     CHIP_ERROR err          = CHIP_NO_ERROR;
     373         1233 :     bool sendStatusResponse = true;
     374         1233 :     if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::StatusResponse))
     375              :     {
     376         1231 :         err = OnStatusResponse(apExchangeContext, std::move(aPayload), sendStatusResponse);
     377              :     }
     378              :     else
     379              :     {
     380            2 :         ChipLogDetail(DataManagement, "ReadHandler:: Msg type %d not supported", aPayloadHeader.GetMessageType());
     381            2 :         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
     382              :     }
     383              : 
     384         1233 :     if (sendStatusResponse)
     385              :     {
     386            4 :         TEMPORARY_RETURN_IGNORED StatusResponse::Send(Status::InvalidAction, apExchangeContext, false /*aExpectResponse*/);
     387              :     }
     388              : 
     389         2466 :     if (err != CHIP_NO_ERROR)
     390              :     {
     391           16 :         Close();
     392              :     }
     393         1233 :     return err;
     394              : }
     395              : 
     396           10 : bool ReadHandler::IsFromSubscriber(Messaging::ExchangeContext & apExchangeContext) const
     397              : {
     398           10 :     return (IsType(InteractionType::Subscribe) &&
     399           30 :             GetInitiatorNodeId() == apExchangeContext.GetSessionHandle()->AsSecureSession()->GetPeerNodeId() &&
     400           20 :             GetAccessingFabricIndex() == apExchangeContext.GetSessionHandle()->GetFabricIndex());
     401              : }
     402              : 
     403            8 : void ReadHandler::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
     404              : {
     405            8 :     ChipLogError(DataManagement, "Time out! failed to receive status response from Exchange: " ChipLogFormatExchange,
     406              :                  ChipLogValueExchange(apExchangeContext));
     407              : #if CHIP_CONFIG_ENABLE_ICD_SERVER && CHIP_CONFIG_ENABLE_ICD_CIP && CHIP_CONFIG_ENABLE_ICD_CHECK_IN_ON_REPORT_TIMEOUT
     408              :     switch (mState)
     409              :     {
     410              :     case HandlerState::AwaitingReportResponse:
     411              :         if (IsType(InteractionType::Subscribe) && !IsPriming())
     412              :         {
     413              :             // Trigger check-in message when a non-priming subscription report times out.
     414              :             ChipLogError(DataManagement, "Trigger check-in message when non-priming subscription report times out");
     415              :             if (mSessionHandle)
     416              :             {
     417              :                 ICDNotifier::GetInstance().NotifySendCheckIn(MakeOptional(GetSubjectDescriptor()));
     418              :             }
     419              :             else
     420              :             {
     421              :                 ChipLogError(DataManagement, "Failed to get subject descriptor for sending check-in message on report timeout");
     422              :             }
     423              :         }
     424              :         break;
     425              :     case HandlerState::CanStartReporting:
     426              :     case HandlerState::Idle:
     427              :     default:
     428              :         break;
     429              :     }
     430              : #endif // CHIP_CONFIG_ENABLE_ICD_CIP && CHIP_CONFIG_ENABLE_ICD_SERVER
     431              : 
     432              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     433            8 :     Close(CloseOptions::kKeepPersistedSubscription);
     434              : #else
     435              :     Close();
     436              : #endif
     437            8 : }
     438              : 
     439          791 : CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle && aPayload)
     440              : {
     441          791 :     CHIP_ERROR err = CHIP_NO_ERROR;
     442          791 :     System::PacketBufferTLVReader reader;
     443              : 
     444          791 :     ReadRequestMessage::Parser readRequestParser;
     445          791 :     EventPathIBs::Parser eventPathListParser;
     446          791 :     EventFilterIBs::Parser eventFilterIBsParser;
     447          791 :     AttributePathIBs::Parser attributePathListParser;
     448              : 
     449          791 :     reader.Init(std::move(aPayload));
     450              : 
     451          791 :     ReturnErrorOnFailure(readRequestParser.Init(reader));
     452              : 
     453              :     // No need to pretty-print here.  We pretty-print read requests in the read
     454              :     // case of InteractionModelEngine::OnReadInitialRequest, so we do it even if
     455              :     // we reject a read request.
     456              : 
     457          791 :     err = readRequestParser.GetAttributeRequests(&attributePathListParser);
     458         1582 :     if (err == CHIP_END_OF_TLV)
     459              :     {
     460          122 :         err = CHIP_NO_ERROR;
     461              :     }
     462         1338 :     else if (err == CHIP_NO_ERROR)
     463              :     {
     464          669 :         ReturnErrorOnFailure(ProcessAttributePaths(attributePathListParser));
     465          669 :         DataVersionFilterIBs::Parser dataVersionFilterListParser;
     466          669 :         err = readRequestParser.GetDataVersionFilters(&dataVersionFilterListParser);
     467         1338 :         if (err == CHIP_END_OF_TLV)
     468              :         {
     469          589 :             err = CHIP_NO_ERROR;
     470              :         }
     471          160 :         else if (err == CHIP_NO_ERROR)
     472              :         {
     473           80 :             ReturnErrorOnFailure(ProcessDataVersionFilterList(dataVersionFilterListParser));
     474              :         }
     475              :     }
     476          791 :     ReturnErrorOnFailure(err);
     477          791 :     err = readRequestParser.GetEventRequests(&eventPathListParser);
     478         1582 :     if (err == CHIP_END_OF_TLV)
     479              :     {
     480          473 :         err = CHIP_NO_ERROR;
     481              :     }
     482          636 :     else if (err == CHIP_NO_ERROR)
     483              :     {
     484          318 :         ReturnErrorOnFailure(err);
     485          318 :         ReturnErrorOnFailure(ProcessEventPaths(eventPathListParser));
     486          318 :         err = readRequestParser.GetEventFilters(&eventFilterIBsParser);
     487          636 :         if (err == CHIP_END_OF_TLV)
     488              :         {
     489            3 :             err = CHIP_NO_ERROR;
     490              :         }
     491          630 :         else if (err == CHIP_NO_ERROR)
     492              :         {
     493          315 :             ReturnErrorOnFailure(ProcessEventFilters(eventFilterIBsParser));
     494              :         }
     495              :     }
     496          791 :     ReturnErrorOnFailure(err);
     497              : 
     498              :     bool isFabricFiltered;
     499          791 :     ReturnErrorOnFailure(readRequestParser.GetIsFabricFiltered(&isFabricFiltered));
     500          787 :     SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
     501          787 :     ReturnErrorOnFailure(readRequestParser.ExitContainer());
     502          787 :     MoveToState(HandlerState::CanStartReporting);
     503              : 
     504          787 :     mExchangeCtx->WillSendMessage();
     505              : 
     506              :     // There must be no code after the WillSendMessage() call that can cause
     507              :     // this method to return a failure.
     508              : 
     509          787 :     return CHIP_NO_ERROR;
     510          791 : }
     511              : 
     512          970 : CHIP_ERROR ReadHandler::ProcessAttributePaths(AttributePathIBs::Parser & aAttributePathListParser)
     513              : {
     514          970 :     CHIP_ERROR err = CHIP_NO_ERROR;
     515          970 :     TLV::TLVReader reader;
     516          970 :     aAttributePathListParser.GetReader(&reader);
     517         5022 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     518              :     {
     519         1541 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     520         1541 :         AttributePathParams attribute;
     521         1541 :         AttributePathIB::Parser path;
     522         1541 :         ReturnErrorOnFailure(path.Init(reader));
     523         1541 :         ReturnErrorOnFailure(path.ParsePath(attribute));
     524         1541 :         ReturnErrorOnFailure(
     525              :             mManagementCallback.GetInteractionModelEngine()->PushFrontAttributePathList(mpAttributePathList, attribute));
     526              :     }
     527              :     // if we have exhausted this container
     528         1940 :     if (CHIP_END_OF_TLV == err)
     529              :     {
     530          970 :         mManagementCallback.GetInteractionModelEngine()->RemoveDuplicateConcreteAttributePath(mpAttributePathList);
     531          970 :         mAttributePathExpandPosition = AttributePathExpandIterator::Position::StartIterating(mpAttributePathList);
     532          970 :         err                          = CHIP_NO_ERROR;
     533              :     }
     534          970 :     return err;
     535              : }
     536              : 
     537          145 : CHIP_ERROR ReadHandler::ProcessDataVersionFilterList(DataVersionFilterIBs::Parser & aDataVersionFilterListParser)
     538              : {
     539          145 :     CHIP_ERROR err = CHIP_NO_ERROR;
     540          145 :     TLV::TLVReader reader;
     541              : 
     542          145 :     aDataVersionFilterListParser.GetReader(&reader);
     543         5274 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     544              :     {
     545         2492 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     546         2492 :         DataVersionFilter versionFilter;
     547         2492 :         ClusterPathIB::Parser path;
     548         2492 :         DataVersionFilterIB::Parser filter;
     549         2492 :         ReturnErrorOnFailure(filter.Init(reader));
     550         2492 :         DataVersion version = 0;
     551         2492 :         ReturnErrorOnFailure(filter.GetDataVersion(&version));
     552         2492 :         versionFilter.mDataVersion.SetValue(version);
     553         2492 :         ReturnErrorOnFailure(filter.GetPath(&path));
     554         2492 :         ReturnErrorOnFailure(path.GetEndpoint(&(versionFilter.mEndpointId)));
     555         2492 :         ReturnErrorOnFailure(path.GetCluster(&(versionFilter.mClusterId)));
     556         2492 :         VerifyOrReturnError(versionFilter.IsValidDataVersionFilter(), CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB);
     557         2492 :         ReturnErrorOnFailure(mManagementCallback.GetInteractionModelEngine()->PushFrontDataVersionFilterList(
     558              :             mpDataVersionFilterList, versionFilter));
     559              :     }
     560              : 
     561          290 :     if (CHIP_END_OF_TLV == err)
     562              :     {
     563          145 :         err = CHIP_NO_ERROR;
     564              :     }
     565          145 :     return err;
     566              : }
     567              : 
     568          336 : CHIP_ERROR ReadHandler::ProcessEventPaths(EventPathIBs::Parser & aEventPathsParser)
     569              : {
     570          336 :     CHIP_ERROR err = CHIP_NO_ERROR;
     571          336 :     TLV::TLVReader reader;
     572          336 :     aEventPathsParser.GetReader(&reader);
     573         1670 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     574              :     {
     575          499 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     576          499 :         EventPathParams event;
     577          499 :         EventPathIB::Parser path;
     578          499 :         ReturnErrorOnFailure(path.Init(reader));
     579          499 :         ReturnErrorOnFailure(path.ParsePath(event));
     580          499 :         ReturnErrorOnFailure(mManagementCallback.GetInteractionModelEngine()->PushFrontEventPathParamsList(mpEventPathList, event));
     581              :     }
     582              : 
     583              :     // if we have exhausted this container
     584          672 :     if (CHIP_END_OF_TLV == err)
     585              :     {
     586          336 :         err = CHIP_NO_ERROR;
     587              :     }
     588          336 :     return err;
     589              : }
     590              : 
     591          315 : CHIP_ERROR ReadHandler::ProcessEventFilters(EventFilterIBs::Parser & aEventFiltersParser)
     592              : {
     593          315 :     CHIP_ERROR err = CHIP_NO_ERROR;
     594          315 :     TLV::TLVReader reader;
     595          315 :     aEventFiltersParser.GetReader(&reader);
     596              : 
     597         1260 :     while (CHIP_NO_ERROR == (err = reader.Next()))
     598              :     {
     599          315 :         VerifyOrReturnError(TLV::AnonymousTag() == reader.GetTag(), CHIP_ERROR_INVALID_TLV_TAG);
     600          315 :         EventFilterIB::Parser filter;
     601          315 :         ReturnErrorOnFailure(filter.Init(reader));
     602              :         // this is for current node, and would have only one event filter.
     603          315 :         ReturnErrorOnFailure(filter.GetEventMin(&(mEventMin)));
     604              :     }
     605          630 :     if (CHIP_END_OF_TLV == err)
     606              :     {
     607          315 :         err = CHIP_NO_ERROR;
     608              :     }
     609          315 :     return err;
     610              : }
     611              : 
     612            0 : const char * ReadHandler::GetStateStr() const
     613              : {
     614              : #if CHIP_DETAIL_LOGGING
     615            0 :     switch (mState)
     616              :     {
     617            0 :     case HandlerState::Idle:
     618            0 :         return "Idle";
     619            0 :     case HandlerState::AwaitingDestruction:
     620            0 :         return "AwaitingDestruction";
     621            0 :     case HandlerState::CanStartReporting:
     622            0 :         return "CanStartReporting";
     623              : 
     624            0 :     case HandlerState::AwaitingReportResponse:
     625            0 :         return "AwaitingReportResponse";
     626              :     }
     627              : #endif // CHIP_DETAIL_LOGGING
     628            0 :     return "N/A";
     629              : }
     630              : 
     631         4428 : void ReadHandler::MoveToState(const HandlerState aTargetState)
     632              : {
     633         4428 :     if (aTargetState == mState)
     634              :     {
     635            0 :         return;
     636              :     }
     637              : 
     638         4428 :     if (IsAwaitingReportResponse() && aTargetState != HandlerState::AwaitingReportResponse)
     639              :     {
     640         1239 :         mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().OnReportConfirm();
     641              :     }
     642              : 
     643         4428 :     mState = aTargetState;
     644         4428 :     ChipLogDetail(DataManagement, "IM RH moving to [%s]", GetStateStr());
     645              : 
     646              :     //
     647              :     // If we just unblocked sending reports, let's go ahead and schedule the reporting
     648              :     // engine to run to kick that off.
     649              :     //
     650         4428 :     if (aTargetState == HandlerState::CanStartReporting)
     651              :     {
     652         2315 :         if (ShouldReportUnscheduled())
     653              :         {
     654         1921 :             TEMPORARY_RETURN_IGNORED mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().ScheduleRun();
     655              :         }
     656              :         else
     657              :         {
     658              :             // If we became reportable, the scheduler will schedule a run as soon as allowed
     659          394 :             mObserver->OnBecameReportable(this);
     660              :         }
     661              :     }
     662              : }
     663              : 
     664          888 : bool ReadHandler::CheckEventClean(EventManagement & aEventManager)
     665              : {
     666          888 :     if (mFlags.Has(ReadHandlerFlags::ChunkedReport))
     667              :     {
     668          525 :         if ((mLastScheduledEventNumber != 0) && (mEventMin <= mLastScheduledEventNumber))
     669              :         {
     670          519 :             return false;
     671              :         }
     672              :     }
     673              :     else
     674              :     {
     675          363 :         EventNumber lastEventNumber = aEventManager.GetLastEventNumber();
     676          363 :         if ((lastEventNumber != 0) && (mEventMin <= lastEventNumber))
     677              :         {
     678              :             // We have more events. snapshot last event number
     679          345 :             aEventManager.SetScheduledEventInfo(mLastScheduledEventNumber, mLastWrittenEventsBytes);
     680          345 :             return false;
     681              :         }
     682              :     }
     683           24 :     return true;
     684              : }
     685              : 
     686          284 : CHIP_ERROR ReadHandler::SendSubscribeResponse()
     687              : {
     688          284 :     System::PacketBufferHandle packet = System::PacketBufferHandle::New(chip::app::kMaxSecureSduLengthBytes);
     689          284 :     VerifyOrReturnLogError(!packet.IsNull(), CHIP_ERROR_NO_MEMORY);
     690              : 
     691          284 :     System::PacketBufferTLVWriter writer;
     692          284 :     writer.Init(std::move(packet));
     693              : 
     694          284 :     SubscribeResponseMessage::Builder response;
     695          284 :     ReturnErrorOnFailure(response.Init(&writer));
     696          284 :     ReturnErrorOnFailure(response.SubscriptionId(mSubscriptionId).MaxInterval(mMaxInterval).EndOfSubscribeResponseMessage());
     697              : 
     698          284 :     ReturnErrorOnFailure(writer.Finalize(&packet));
     699          284 :     VerifyOrReturnLogError(mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     700              : 
     701          284 :     ClearStateFlag(ReadHandlerFlags::PrimingReports);
     702          284 :     return mExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::SubscribeResponse, std::move(packet));
     703          284 : }
     704              : 
     705          307 : CHIP_ERROR ReadHandler::ProcessSubscribeRequest(System::PacketBufferHandle && aPayload)
     706              : {
     707          307 :     System::PacketBufferTLVReader reader;
     708          307 :     reader.Init(std::move(aPayload));
     709              : 
     710          307 :     SubscribeRequestMessage::Parser subscribeRequestParser;
     711          307 :     ReturnErrorOnFailure(subscribeRequestParser.Init(reader));
     712              : 
     713              :     // No need to pretty-print here.  We pretty-print subscribe requests in the
     714              :     // subscribe case of InteractionModelEngine::OnReadInitialRequest, so we do
     715              :     // it even if we reject a subscribe request.
     716              : 
     717          307 :     AttributePathIBs::Parser attributePathListParser;
     718          307 :     CHIP_ERROR err = subscribeRequestParser.GetAttributeRequests(&attributePathListParser);
     719          614 :     if (err == CHIP_END_OF_TLV)
     720              :     {
     721            6 :         err = CHIP_NO_ERROR;
     722              :     }
     723          602 :     else if (err == CHIP_NO_ERROR)
     724              :     {
     725          301 :         ReturnErrorOnFailure(ProcessAttributePaths(attributePathListParser));
     726          301 :         DataVersionFilterIBs::Parser dataVersionFilterListParser;
     727          301 :         err = subscribeRequestParser.GetDataVersionFilters(&dataVersionFilterListParser);
     728          602 :         if (err == CHIP_END_OF_TLV)
     729              :         {
     730          236 :             err = CHIP_NO_ERROR;
     731              :         }
     732          130 :         else if (err == CHIP_NO_ERROR)
     733              :         {
     734           65 :             ReturnErrorOnFailure(ProcessDataVersionFilterList(dataVersionFilterListParser));
     735              :         }
     736              :     }
     737          307 :     ReturnErrorOnFailure(err);
     738              : 
     739          307 :     EventPathIBs::Parser eventPathListParser;
     740          307 :     err = subscribeRequestParser.GetEventRequests(&eventPathListParser);
     741          614 :     if (err == CHIP_END_OF_TLV)
     742              :     {
     743          289 :         err = CHIP_NO_ERROR;
     744              :     }
     745           36 :     else if (err == CHIP_NO_ERROR)
     746              :     {
     747           18 :         ReturnErrorOnFailure(ProcessEventPaths(eventPathListParser));
     748           18 :         EventFilterIBs::Parser eventFilterIBsParser;
     749           18 :         err = subscribeRequestParser.GetEventFilters(&eventFilterIBsParser);
     750           36 :         if (err == CHIP_END_OF_TLV)
     751              :         {
     752           18 :             err = CHIP_NO_ERROR;
     753              :         }
     754            0 :         else if (err == CHIP_NO_ERROR)
     755              :         {
     756            0 :             ReturnErrorOnFailure(ProcessEventFilters(eventFilterIBsParser));
     757              :         }
     758              :     }
     759          307 :     ReturnErrorOnFailure(err);
     760              : 
     761          307 :     ReturnErrorOnFailure(subscribeRequestParser.GetMinIntervalFloorSeconds(&mMinIntervalFloorSeconds));
     762          307 :     ReturnErrorOnFailure(subscribeRequestParser.GetMaxIntervalCeilingSeconds(&mSubscriberRequestedMaxInterval));
     763          307 :     mMaxInterval = mSubscriberRequestedMaxInterval;
     764              : 
     765          307 :     VerifyOrReturnError(mMinIntervalFloorSeconds <= mMaxInterval, CHIP_ERROR_INVALID_ARGUMENT);
     766              : 
     767              : #if CHIP_CONFIG_ENABLE_ICD_SERVER
     768              : 
     769              :     // To optimize ICD sleep/idle cycles, it is preferred to synchronize the subscription report interval
     770              :     // with the IdleModeDuration defined in the ICD Management Cluster.
     771              :     // We aim to use IdleModeDuration, but must respect the Min Interval Floor and Max Interval Ceiling.
     772              :     // Note: This behavior can be overridden using the OnSubscriptionRequested callback defined
     773              :     // in the application.
     774              : 
     775              :     // Per spec and static checks, GetIdleModeDuration max value fits a uint16_t.
     776              :     // The final selected interval must be a uint16_t but we use a uint32 here during calculation to prevent overflows.
     777              :     uint32_t preferredMaxInterval = ICDConfigurationData::GetInstance().GetIdleModeDuration().count();
     778              :     // Determine the max interval ceiling between GetPublisherSelectedIntervalLimit
     779              :     // and the subscriber-requested MaxInterval.
     780              :     uint16_t maxIntervalCeiling = std::max(GetPublisherSelectedIntervalLimit(), mMaxInterval);
     781              : 
     782              :     // Spec doesn't allow IdleModeDuration of 0 but make sure here to prevent div0
     783              :     if (preferredMaxInterval == 0)
     784              :     {
     785              :         preferredMaxInterval = maxIntervalCeiling;
     786              :     }
     787              :     else
     788              :     {
     789              :         // Must respect the minimal interval floor
     790              :         if (preferredMaxInterval < mMinIntervalFloorSeconds)
     791              :         {
     792              :             // Round up to the nearest multiple of IdleModeDuration that is >= mMinIntervalFloorSeconds.
     793              :             const uint32_t remainder = mMinIntervalFloorSeconds % preferredMaxInterval;
     794              :             preferredMaxInterval =
     795              :                 remainder == 0 ? mMinIntervalFloorSeconds : (mMinIntervalFloorSeconds + (preferredMaxInterval - remainder));
     796              :         }
     797              : 
     798              :         // Use the smallest interval between preferredMaxInterval and maxIntervalCeiling.
     799              :         // This also ensure that no overflow occurs when casting to uint16_t below
     800              :         preferredMaxInterval = std::min<uint32_t>(preferredMaxInterval, maxIntervalCeiling);
     801              :     }
     802              :     mMaxInterval = static_cast<uint16_t>(preferredMaxInterval);
     803              : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
     804              : 
     805              :     //
     806              :     // Notify the application (if requested) of the impending subscription and check whether we should still proceed to set it up.
     807              :     // This also provides the application an opportunity to modify the negotiated min/max intervals set above.
     808              :     //
     809          307 :     auto * appCallback = mManagementCallback.GetAppCallback();
     810          307 :     if (appCallback)
     811              :     {
     812          494 :         if (appCallback->OnSubscriptionRequested(*this, *mExchangeCtx->GetSessionHandle()->AsSecureSession()) != CHIP_NO_ERROR)
     813              :         {
     814            6 :             return CHIP_ERROR_TRANSACTION_CANCELED;
     815              :         }
     816              :     }
     817              : 
     818          301 :     ChipLogProgress(DataManagement, "Final negotiated min/max parameters: Min = %ds, Max = %ds", mMinIntervalFloorSeconds,
     819              :                     mMaxInterval);
     820              : 
     821              :     bool isFabricFiltered;
     822          301 :     ReturnErrorOnFailure(subscribeRequestParser.GetIsFabricFiltered(&isFabricFiltered));
     823          301 :     SetStateFlag(ReadHandlerFlags::FabricFiltered, isFabricFiltered);
     824          301 :     ReturnErrorOnFailure(Crypto::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&mSubscriptionId), sizeof(mSubscriptionId)));
     825          301 :     ReturnErrorOnFailure(subscribeRequestParser.ExitContainer());
     826          301 :     MoveToState(HandlerState::CanStartReporting);
     827              : 
     828          301 :     mExchangeCtx->WillSendMessage();
     829              : 
     830              : #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     831          301 :     PersistSubscription();
     832              : #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS
     833              : 
     834          301 :     return CHIP_NO_ERROR;
     835          307 : }
     836              : 
     837          301 : void ReadHandler::PersistSubscription()
     838              : {
     839          301 :     auto * subscriptionResumptionStorage = mManagementCallback.GetInteractionModelEngine()->GetSubscriptionResumptionStorage();
     840          301 :     VerifyOrReturn(subscriptionResumptionStorage != nullptr);
     841              : 
     842              :     // TODO(#31873): We need to store the CAT information to enable better interactions with ICDs
     843            0 :     SubscriptionResumptionStorage::SubscriptionInfo subscriptionInfo = { .mNodeId         = GetInitiatorNodeId(),
     844            0 :                                                                          .mFabricIndex    = GetAccessingFabricIndex(),
     845            0 :                                                                          .mSubscriptionId = mSubscriptionId,
     846            0 :                                                                          .mMinInterval    = mMinIntervalFloorSeconds,
     847            0 :                                                                          .mMaxInterval    = mMaxInterval,
     848            0 :                                                                          .mFabricFiltered = IsFabricFiltered() };
     849            0 :     VerifyOrReturn(subscriptionInfo.SetAttributePaths(mpAttributePathList) == CHIP_NO_ERROR);
     850            0 :     VerifyOrReturn(subscriptionInfo.SetEventPaths(mpEventPathList) == CHIP_NO_ERROR);
     851              : 
     852            0 :     CHIP_ERROR err = subscriptionResumptionStorage->Save(subscriptionInfo);
     853            0 :     if (err != CHIP_NO_ERROR)
     854              :     {
     855            0 :         ChipLogError(DataManagement, "Failed to save subscription info error: '%" CHIP_ERROR_FORMAT, err.Format());
     856              :     }
     857            0 : }
     858              : 
     859         1168 : void ReadHandler::ResetPathIterator()
     860              : {
     861         1168 :     mAttributePathExpandPosition = AttributePathExpandIterator::Position::StartIterating(mpAttributePathList);
     862         1168 :     mAttributeEncoderState.Reset();
     863         1168 : }
     864              : 
     865          348 : void ReadHandler::AttributePathIsDirty(DataModel::Provider * apDataModel, const AttributePathParams & aAttributeChanged)
     866              : {
     867          348 :     mDirtyGeneration = mManagementCallback.GetInteractionModelEngine()->GetReportingEngine().GetDirtySetGeneration();
     868              : 
     869              :     // We want to get the value, but not advance the iterator position.
     870          348 :     AttributePathExpandIterator::Position tempPosition = mAttributePathExpandPosition;
     871          348 :     ConcreteAttributePath path;
     872              : 
     873              :     // We won't reset the path iterator for every AttributePathIsDirty call to reduce the number of full data reports.
     874              :     // The iterator will be reset after finishing each report session.
     875              :     //
     876              :     // Here we just reset the iterator to the beginning of the current cluster, if the dirty path affects it.
     877              :     // This will ensure the reports are consistent within a single cluster generated from a single path in the request.
     878              : 
     879              :     // TODO (#16699): Currently we can only guarantee the reports generated from a single path in the request are consistent. The
     880              :     // data might be inconsistent if the user send a request with two paths from the same cluster. We need to clearify the behavior
     881              :     // or make it consistent.
     882          614 :     if (AttributePathExpandIterator(apDataModel, tempPosition).Next(path) &&
     883         1141 :         (aAttributeChanged.HasWildcardEndpointId() || aAttributeChanged.mEndpointId == path.mEndpointId) &&
     884          527 :         (aAttributeChanged.HasWildcardClusterId() || aAttributeChanged.mClusterId == path.mClusterId))
     885              :     {
     886          264 :         ChipLogDetail(DataManagement,
     887              :                       "The dirty path intersects the cluster we are currently reporting; reset the iterator to the beginning of "
     888              :                       "that cluster");
     889              :         // If we're currently in the middle of generating reports for a given cluster and that in turn is marked dirty, let's reset
     890              :         // our iterator to point back to the beginning of that cluster. This ensures that the receiver will get a coherent view of
     891              :         // the state of the cluster as present on the server
     892          264 :         mAttributePathExpandPosition.IterateFromTheStartOfTheCurrentClusterIfAttributeWildcard();
     893              : 
     894          264 :         mAttributeEncoderState.Reset();
     895              :     }
     896              : 
     897              :     // ReportScheduler will take care of verifying the reportability of the handler and schedule the run
     898          348 :     mObserver->OnBecameReportable(this);
     899          348 : }
     900              : 
     901        15109 : Transport::SecureSession * ReadHandler::GetSession() const
     902              : {
     903        15109 :     if (!mSessionHandle)
     904              :     {
     905            0 :         return nullptr;
     906              :     }
     907        15109 :     return mSessionHandle->AsSecureSession();
     908              : }
     909              : 
     910           19 : void ReadHandler::ForceDirtyState()
     911              : {
     912           19 :     SetStateFlag(ReadHandlerFlags::ForceDirty);
     913           19 : }
     914              : 
     915         6964 : void ReadHandler::SetStateFlag(ReadHandlerFlags aFlag, bool aValue)
     916              : {
     917         6964 :     bool oldReportable = ShouldStartReporting();
     918         6964 :     mFlags.Set(aFlag, aValue);
     919              : 
     920              :     // If we became reportable, schedule a reporting run.
     921         6964 :     if (!oldReportable && ShouldStartReporting())
     922              :     {
     923              :         // If we became reportable, the scheduler will schedule a run as soon as allowed
     924           13 :         mObserver->OnBecameReportable(this);
     925              :     }
     926         6964 : }
     927              : 
     928         1382 : void ReadHandler::ClearStateFlag(ReadHandlerFlags aFlag)
     929              : {
     930         1382 :     SetStateFlag(aFlag, false);
     931         1382 : }
     932              : 
     933         1980 : size_t ReadHandler::GetReportBufferMaxSize()
     934              : {
     935         1980 :     Transport::SecureSession * session = GetSession();
     936         1980 :     if (session && session->AllowsLargePayload())
     937              :     {
     938            0 :         return kMaxLargeSecureSduLengthBytes;
     939              :     }
     940         1980 :     return kMaxSecureSduLengthBytes;
     941              : }
     942              : 
     943              : } // namespace app
     944              : } // namespace chip
        

Generated by: LCOV version 2.0-1