LCOV - code coverage report
Current view: top level - app - EventManagement.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 411 428 96.0 %
Date: 2024-02-15 08:20:41 Functions: 31 32 96.9 %

          Line data    Source code
       1             : /**
       2             :  *
       3             :  *    Copyright (c) 2021 Project CHIP Authors
       4             :  *    Copyright (c) 2015-2017 Nest Labs, Inc.
       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             : 
      19             : #include <access/AccessControl.h>
      20             : #include <access/RequestPath.h>
      21             : #include <access/SubjectDescriptor.h>
      22             : #include <app/EventManagement.h>
      23             : #include <app/InteractionModelEngine.h>
      24             : #include <app/RequiredPrivilege.h>
      25             : #include <assert.h>
      26             : #include <inttypes.h>
      27             : #include <lib/core/TLVUtilities.h>
      28             : #include <lib/support/CodeUtils.h>
      29             : #include <lib/support/logging/CHIPLogging.h>
      30             : 
      31             : using namespace chip::TLV;
      32             : 
      33             : namespace chip {
      34             : namespace app {
      35             : static EventManagement sInstance;
      36             : 
      37             : /**
      38             :  * @brief
      39             :  *   A TLVReader backed by CircularEventBuffer
      40             :  */
      41             : class CircularEventReader : public TLV::TLVReader
      42             : {
      43             : public:
      44             :     /**
      45             :      * @brief
      46             :      *   Initializes a TLVReader object backed by CircularEventBuffer
      47             :      *
      48             :      * Reading begins in the CircularTLVBuffer belonging to this
      49             :      * CircularEventBuffer.  When the reader runs out of data, it begins
      50             :      * to read from the previous CircularEventBuffer.
      51             :      *
      52             :      * @param[in] apBuf A pointer to a fully initialized CircularEventBuffer
      53             :      *
      54             :      */
      55             :     void Init(CircularEventBufferWrapper * apBuf);
      56             : 
      57         943 :     virtual ~CircularEventReader() = default;
      58             : };
      59             : 
      60        1928 : EventManagement & EventManagement::GetInstance()
      61             : {
      62        1928 :     return sInstance;
      63             : }
      64             : 
      65             : struct ReclaimEventCtx
      66             : {
      67             :     CircularEventBuffer * mpEventBuffer = nullptr;
      68             :     size_t mSpaceNeededForMovedEvent    = 0;
      69             : };
      70             : 
      71             : /**
      72             :  * @brief
      73             :  *  Internal structure for traversing event list.
      74             :  */
      75             : struct CopyAndAdjustDeltaTimeContext
      76             : {
      77        2163 :     CopyAndAdjustDeltaTimeContext(TLVWriter * aWriter, EventLoadOutContext * inContext) : mpWriter(aWriter), mpContext(inContext) {}
      78             : 
      79             :     TLV::TLVWriter * mpWriter       = nullptr;
      80             :     EventLoadOutContext * mpContext = nullptr;
      81             : };
      82             : 
      83         123 : void EventManagement::Init(Messaging::ExchangeManager * apExchangeManager, uint32_t aNumBuffers,
      84             :                            CircularEventBuffer * apCircularEventBuffer, const LogStorageResources * const apLogStorageResources,
      85             :                            MonotonicallyIncreasingCounter<EventNumber> * apEventNumberCounter,
      86             :                            System::Clock::Milliseconds64 aMonotonicStartupTime)
      87             : {
      88         123 :     CircularEventBuffer * current = nullptr;
      89         123 :     CircularEventBuffer * prev    = nullptr;
      90         123 :     CircularEventBuffer * next    = nullptr;
      91             : 
      92         123 :     if (aNumBuffers == 0)
      93             :     {
      94           0 :         ChipLogError(EventLogging, "Invalid aNumBuffers");
      95           0 :         return;
      96             :     }
      97             : 
      98         123 :     if (mState != EventManagementStates::Shutdown)
      99             :     {
     100           0 :         ChipLogError(EventLogging, "Invalid EventManagement State");
     101           0 :         return;
     102             :     }
     103         123 :     mpExchangeMgr = apExchangeManager;
     104             : 
     105         492 :     for (uint32_t bufferIndex = 0; bufferIndex < aNumBuffers; bufferIndex++)
     106             :     {
     107         369 :         next = (bufferIndex < aNumBuffers - 1) ? &apCircularEventBuffer[bufferIndex + 1] : nullptr;
     108             : 
     109         369 :         current = &apCircularEventBuffer[bufferIndex];
     110         369 :         current->Init(apLogStorageResources[bufferIndex].mpBuffer, apLogStorageResources[bufferIndex].mBufferSize, prev, next,
     111         369 :                       apLogStorageResources[bufferIndex].mPriority);
     112             : 
     113         369 :         prev = current;
     114             : 
     115         369 :         current->mProcessEvictedElement = nullptr;
     116         369 :         current->mAppData               = nullptr;
     117             :     }
     118             : 
     119         123 :     mpEventNumberCounter = apEventNumberCounter;
     120         123 :     mLastEventNumber     = mpEventNumberCounter->GetValue();
     121             : 
     122         123 :     mpEventBuffer = apCircularEventBuffer;
     123         123 :     mState        = EventManagementStates::Idle;
     124         123 :     mBytesWritten = 0;
     125             : 
     126         123 :     mMonotonicStartupTime = aMonotonicStartupTime;
     127             : }
     128             : 
     129         422 : CHIP_ERROR EventManagement::CopyToNextBuffer(CircularEventBuffer * apEventBuffer)
     130             : {
     131         422 :     CircularTLVWriter writer;
     132             :     CircularTLVReader reader;
     133         422 :     CHIP_ERROR err                   = CHIP_NO_ERROR;
     134         422 :     CircularEventBuffer * nextBuffer = apEventBuffer->GetNextCircularEventBuffer();
     135         422 :     if (nextBuffer == nullptr)
     136             :     {
     137           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     138             :     }
     139         422 :     CircularEventBuffer backup = *nextBuffer;
     140             : 
     141             :     // Set up the next buffer s.t. it fails if needs to evict an element
     142         422 :     nextBuffer->mProcessEvictedElement = AlwaysFail;
     143             : 
     144         422 :     writer.Init(*nextBuffer);
     145             : 
     146             :     // Set up the reader s.t. it is positioned to read the head event
     147         422 :     reader.Init(*apEventBuffer);
     148             : 
     149         422 :     err = reader.Next();
     150         422 :     SuccessOrExit(err);
     151             : 
     152         422 :     err = writer.CopyElement(reader);
     153         422 :     SuccessOrExit(err);
     154             : 
     155         422 :     err = writer.Finalize();
     156         422 :     SuccessOrExit(err);
     157             : 
     158         422 :     ChipLogDetail(EventLogging, "Copy Event to next buffer with priority %u", static_cast<unsigned>(nextBuffer->GetPriority()));
     159           0 : exit:
     160         422 :     if (err != CHIP_NO_ERROR)
     161             :     {
     162           0 :         *nextBuffer = backup;
     163             :     }
     164         422 :     return err;
     165         422 : }
     166             : 
     167         662 : CHIP_ERROR EventManagement::EnsureSpaceInCircularBuffer(size_t aRequiredSpace, PriorityLevel aPriority)
     168             : {
     169         662 :     CHIP_ERROR err                    = CHIP_NO_ERROR;
     170         662 :     size_t requiredSpace              = aRequiredSpace;
     171         662 :     CircularEventBuffer * eventBuffer = mpEventBuffer;
     172         662 :     ReclaimEventCtx ctx;
     173             : 
     174             :     // Check that we have this much space in all our event buffers that might
     175             :     // hold the event. If we do not, that will prevent the event from being
     176             :     // properly evicted into higher-priority buffers. We want to discover
     177             :     // this early, so that testing surfaces the need to make those buffers
     178             :     // larger.
     179        1366 :     for (auto * currentBuffer = mpEventBuffer; currentBuffer; currentBuffer = currentBuffer->GetNextCircularEventBuffer())
     180             :     {
     181        1366 :         VerifyOrExit(requiredSpace <= currentBuffer->GetTotalDataLength(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
     182        1366 :         if (currentBuffer->IsFinalDestinationForPriority(aPriority))
     183             :         {
     184         662 :             break;
     185             :         }
     186             :     }
     187             : 
     188         662 :     VerifyOrExit(eventBuffer != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
     189             : 
     190             :     // check whether we actually need to do anything, exit if we don't
     191         662 :     VerifyOrExit(requiredSpace > eventBuffer->AvailableDataLength(), err = CHIP_NO_ERROR);
     192             : 
     193             :     while (true)
     194             :     {
     195        1884 :         if (requiredSpace > eventBuffer->AvailableDataLength())
     196             :         {
     197        1100 :             ctx.mpEventBuffer             = eventBuffer;
     198        1100 :             ctx.mSpaceNeededForMovedEvent = 0;
     199             : 
     200        1100 :             eventBuffer->mProcessEvictedElement = EvictEvent;
     201        1100 :             eventBuffer->mAppData               = &ctx;
     202        1100 :             err                                 = eventBuffer->EvictHead();
     203             : 
     204             :             // one of two things happened: either the element was evicted immediately if the head's priority is same as current
     205             :             // buffer(final one), or we figured out how much space we need to evict it into the next buffer, the check happens in
     206             :             // EvictEvent function
     207             : 
     208        1100 :             if (err != CHIP_NO_ERROR)
     209             :             {
     210         735 :                 VerifyOrExit(ctx.mSpaceNeededForMovedEvent != 0, /* no-op, return err */);
     211         735 :                 VerifyOrExit(eventBuffer->GetNextCircularEventBuffer() != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
     212         735 :                 if (ctx.mSpaceNeededForMovedEvent <= eventBuffer->GetNextCircularEventBuffer()->AvailableDataLength())
     213             :                 {
     214             :                     // we can copy the event outright.  copy event and
     215             :                     // subsequently evict head s.t. evicting the head
     216             :                     // element always succeeds.
     217             :                     // Since we're calling CopyElement and we've checked
     218             :                     // that there is space in the next buffer, we don't expect
     219             :                     // this to fail.
     220         422 :                     err = CopyToNextBuffer(eventBuffer);
     221         422 :                     SuccessOrExit(err);
     222             :                     // success; evict head unconditionally
     223         422 :                     eventBuffer->mProcessEvictedElement = nullptr;
     224         422 :                     err                                 = eventBuffer->EvictHead();
     225             :                     // if unconditional eviction failed, this
     226             :                     // means that we have no way of further
     227             :                     // clearing the buffer.  fail out and let the
     228             :                     // caller know that we could not honor the
     229             :                     // request
     230         422 :                     SuccessOrExit(err);
     231         422 :                     continue;
     232             :                 }
     233             :                 // we cannot copy event outright. We remember the
     234             :                 // current required space in mRequiredSpaceForEvicted, we note the
     235             :                 // space requirements for the event in the current
     236             :                 // buffer and make that space in the next buffer.
     237         313 :                 eventBuffer->SetRequiredSpaceforEvicted(requiredSpace);
     238         313 :                 eventBuffer = eventBuffer->GetNextCircularEventBuffer();
     239             : 
     240             :                 // Sanity check: return error  here on null event buffer.  If
     241             :                 // eventBuffer->mpNext were null, then the `EvictBuffer`
     242             :                 // would have succeeded -- the event was
     243             :                 // already in the final buffer.
     244         313 :                 VerifyOrExit(eventBuffer != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
     245         313 :                 requiredSpace = ctx.mSpaceNeededForMovedEvent;
     246             :             }
     247             :         }
     248             :         else
     249             :         {
     250             :             // this branch is only taken when we go back in the buffer chain since we have free/spare enough space in next buffer,
     251             :             // and need to retry to copy event from current buffer to next buffer, and free space for current buffer
     252         784 :             if (eventBuffer == mpEventBuffer)
     253         471 :                 break;
     254         313 :             eventBuffer   = eventBuffer->GetPreviousCircularEventBuffer();
     255         313 :             requiredSpace = eventBuffer->GetRequiredSpaceforEvicted();
     256         313 :             err           = CHIP_NO_ERROR;
     257             :         }
     258             :     }
     259             : 
     260         471 :     mpEventBuffer->mProcessEvictedElement = nullptr;
     261         471 :     mpEventBuffer->mAppData               = nullptr;
     262             : 
     263         662 : exit:
     264         662 :     return err;
     265             : }
     266             : 
     267         662 : CHIP_ERROR EventManagement::CalculateEventSize(EventLoggingDelegate * apDelegate, const EventOptions * apOptions,
     268             :                                                uint32_t & requiredSize)
     269             : {
     270         662 :     System::PacketBufferTLVWriter writer;
     271         662 :     EventLoadOutContext ctxt       = EventLoadOutContext(writer, apOptions->mPriority, GetLastEventNumber());
     272         662 :     System::PacketBufferHandle buf = System::PacketBufferHandle::New(kMaxEventSizeReserve);
     273         662 :     if (buf.IsNull())
     274             :     {
     275           0 :         return CHIP_ERROR_NO_MEMORY;
     276             :     }
     277         662 :     writer.Init(std::move(buf));
     278             : 
     279         662 :     ctxt.mCurrentEventNumber = mLastEventNumber;
     280         662 :     ctxt.mCurrentTime        = mLastEventTimestamp;
     281         662 :     CHIP_ERROR err           = ConstructEvent(&ctxt, apDelegate, apOptions);
     282         662 :     if (err == CHIP_NO_ERROR)
     283             :     {
     284         662 :         requiredSize = writer.GetLengthWritten();
     285             :     }
     286         662 :     return err;
     287         662 : }
     288             : 
     289        1324 : CHIP_ERROR EventManagement::ConstructEvent(EventLoadOutContext * apContext, EventLoggingDelegate * apDelegate,
     290             :                                            const EventOptions * apOptions)
     291             : {
     292        1324 :     VerifyOrReturnError(apContext->mCurrentEventNumber >= apContext->mStartingEventNumber, CHIP_NO_ERROR
     293             :                         /* no-op: don't write event, but advance current event Number */);
     294             : 
     295        1324 :     VerifyOrReturnError(apOptions != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     296             : 
     297        1324 :     EventReportIB::Builder eventReportBuilder;
     298        1324 :     ReturnErrorOnFailure(eventReportBuilder.Init(&(apContext->mWriter)));
     299        1324 :     EventDataIB::Builder & eventDataIBBuilder = eventReportBuilder.CreateEventData();
     300        1324 :     ReturnErrorOnFailure(eventReportBuilder.GetError());
     301        1324 :     EventPathIB::Builder & eventPathBuilder = eventDataIBBuilder.CreatePath();
     302        1324 :     ReturnErrorOnFailure(eventDataIBBuilder.GetError());
     303             : 
     304        1324 :     CHIP_ERROR err = eventPathBuilder.Endpoint(apOptions->mPath.mEndpointId)
     305        1324 :                          .Cluster(apOptions->mPath.mClusterId)
     306        1324 :                          .Event(apOptions->mPath.mEventId)
     307        1324 :                          .EndOfEventPathIB();
     308        1324 :     ReturnErrorOnFailure(err);
     309        1324 :     eventDataIBBuilder.EventNumber(apContext->mCurrentEventNumber).Priority(chip::to_underlying(apContext->mPriority));
     310        1324 :     ReturnErrorOnFailure(eventDataIBBuilder.GetError());
     311             : 
     312        1324 :     if (apOptions->mTimestamp.IsSystem())
     313             :     {
     314          24 :         eventDataIBBuilder.SystemTimestamp(apOptions->mTimestamp.mValue);
     315             :     }
     316             :     else
     317             :     {
     318        1300 :         eventDataIBBuilder.EpochTimestamp(apOptions->mTimestamp.mValue);
     319             :     }
     320             : 
     321        1324 :     ReturnErrorOnFailure(eventDataIBBuilder.GetError());
     322             : 
     323             :     // Callback to write the EventData
     324        1324 :     ReturnErrorOnFailure(apDelegate->WriteEvent(apContext->mWriter));
     325             : 
     326             :     // The fabricIndex profile tag is internal use only for fabric filtering when retrieving event from circular event buffer,
     327             :     // and would not go on the wire.
     328             :     // Revisit FabricRemovedCB function should the encoding of fabricIndex change in the future.
     329        1324 :     if (apOptions->mFabricIndex != kUndefinedFabricIndex)
     330             :     {
     331           8 :         apContext->mWriter.Put(TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag), apOptions->mFabricIndex);
     332             :     }
     333        1324 :     ReturnErrorOnFailure(eventDataIBBuilder.EndOfEventDataIB());
     334        1324 :     ReturnErrorOnFailure(eventReportBuilder.EndOfEventReportIB());
     335        1324 :     ReturnErrorOnFailure(apContext->mWriter.Finalize());
     336        1324 :     apContext->mFirst = false;
     337        1324 :     return CHIP_NO_ERROR;
     338             : }
     339             : 
     340         122 : void EventManagement::CreateEventManagement(Messaging::ExchangeManager * apExchangeManager, uint32_t aNumBuffers,
     341             :                                             CircularEventBuffer * apCircularEventBuffer,
     342             :                                             const LogStorageResources * const apLogStorageResources,
     343             :                                             MonotonicallyIncreasingCounter<EventNumber> * apEventNumberCounter,
     344             :                                             System::Clock::Milliseconds64 aMonotonicStartupTime)
     345             : {
     346             : 
     347         122 :     sInstance.Init(apExchangeManager, aNumBuffers, apCircularEventBuffer, apLogStorageResources, apEventNumberCounter,
     348             :                    aMonotonicStartupTime);
     349         122 : }
     350             : 
     351             : /**
     352             :  * @brief Perform any actions we need to on shutdown.
     353             :  */
     354         122 : void EventManagement::DestroyEventManagement()
     355             : {
     356         122 :     sInstance.mState        = EventManagementStates::Shutdown;
     357         122 :     sInstance.mpEventBuffer = nullptr;
     358         122 :     sInstance.mpExchangeMgr = nullptr;
     359         122 : }
     360             : 
     361         943 : CircularEventBuffer * EventManagement::GetPriorityBuffer(PriorityLevel aPriority) const
     362             : {
     363         943 :     CircularEventBuffer * buf = mpEventBuffer;
     364        2757 :     while (!buf->IsFinalDestinationForPriority(aPriority))
     365             :     {
     366        1814 :         buf = buf->GetNextCircularEventBuffer();
     367        1814 :         assert(buf != nullptr);
     368             :         // code guarantees that every PriorityLevel has a buffer destination.
     369             :     }
     370         943 :     return buf;
     371             : }
     372             : 
     373       10097 : CHIP_ERROR EventManagement::CopyAndAdjustDeltaTime(const TLVReader & aReader, size_t aDepth, void * apContext)
     374             : {
     375       10097 :     CopyAndAdjustDeltaTimeContext * ctx = static_cast<CopyAndAdjustDeltaTimeContext *>(apContext);
     376       10097 :     TLVReader reader(aReader);
     377             : 
     378       10097 :     if (aReader.GetTag() == TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag))
     379             :     {
     380             :         // Does not go on the wire.
     381          13 :         return CHIP_NO_ERROR;
     382             :     }
     383       10105 :     if ((aReader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kSystemTimestamp)) && !(ctx->mpContext->mFirst) &&
     384          21 :         (ctx->mpContext->mCurrentTime.mType == ctx->mpContext->mPreviousTime.mType))
     385             :     {
     386          21 :         return ctx->mpWriter->Put(TLV::ContextTag(EventDataIB::Tag::kDeltaSystemTimestamp),
     387          42 :                                   ctx->mpContext->mCurrentTime.mValue - ctx->mpContext->mPreviousTime.mValue);
     388             :     }
     389       11236 :     if ((aReader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kEpochTimestamp)) && !(ctx->mpContext->mFirst) &&
     390        1173 :         (ctx->mpContext->mCurrentTime.mType == ctx->mpContext->mPreviousTime.mType))
     391             :     {
     392           0 :         return ctx->mpWriter->Put(TLV::ContextTag(EventDataIB::Tag::kDeltaEpochTimestamp),
     393           0 :                                   ctx->mpContext->mCurrentTime.mValue - ctx->mpContext->mPreviousTime.mValue);
     394             :     }
     395             : 
     396       10063 :     return ctx->mpWriter->CopyElement(reader);
     397             : }
     398             : 
     399         662 : void EventManagement::VendEventNumber()
     400             : {
     401         662 :     CHIP_ERROR err = CHIP_NO_ERROR;
     402             :     // Now advance the counter.
     403         662 :     err = mpEventNumberCounter->Advance();
     404         662 :     if (err != CHIP_NO_ERROR)
     405             :     {
     406           0 :         ChipLogError(EventLogging, "%s Advance() failed with %" CHIP_ERROR_FORMAT, __FUNCTION__, err.Format());
     407             :     }
     408             : 
     409             :     // Assign event Number to the buffer's counter's value.
     410         662 :     mLastEventNumber = mpEventNumberCounter->GetValue();
     411         662 : }
     412             : 
     413         662 : CHIP_ERROR EventManagement::LogEvent(EventLoggingDelegate * apDelegate, const EventOptions & aEventOptions,
     414             :                                      EventNumber & aEventNumber)
     415             : {
     416         662 :     assertChipStackLockedByCurrentThread();
     417         662 :     VerifyOrReturnError(mState != EventManagementStates::Shutdown, CHIP_ERROR_INCORRECT_STATE);
     418         662 :     return LogEventPrivate(apDelegate, aEventOptions, aEventNumber);
     419             : }
     420             : 
     421         662 : CHIP_ERROR EventManagement::LogEventPrivate(EventLoggingDelegate * apDelegate, const EventOptions & aEventOptions,
     422             :                                             EventNumber & aEventNumber)
     423             : {
     424         662 :     CircularTLVWriter writer;
     425         662 :     CHIP_ERROR err               = CHIP_NO_ERROR;
     426         662 :     uint32_t requestSize         = 0;
     427         662 :     aEventNumber                 = 0;
     428         662 :     CircularTLVWriter checkpoint = writer;
     429         662 :     EventLoadOutContext ctxt     = EventLoadOutContext(writer, aEventOptions.mPriority, mLastEventNumber);
     430         662 :     EventOptions opts;
     431             : 
     432         662 :     Timestamp timestamp;
     433             : #if CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
     434             :     System::Clock::Milliseconds64 utc_time;
     435         662 :     err = System::SystemClock().GetClock_RealTimeMS(utc_time);
     436         662 :     if (err == CHIP_NO_ERROR)
     437             :     {
     438         650 :         timestamp = Timestamp::Epoch(utc_time);
     439             :     }
     440             :     else
     441             : #endif // CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
     442             :     {
     443          12 :         auto systemTimeMs = System::SystemClock().GetMonotonicMilliseconds64() - mMonotonicStartupTime;
     444          12 :         timestamp         = Timestamp::System(systemTimeMs);
     445             :     }
     446             : 
     447         662 :     opts = EventOptions(timestamp);
     448             :     // Start the event container (anonymous structure) in the circular buffer
     449         662 :     writer.Init(*mpEventBuffer);
     450             : 
     451         662 :     opts.mPriority = aEventOptions.mPriority;
     452             :     // Create all event specific data
     453             :     // Timestamp; encoded as a delta time
     454             : 
     455         662 :     opts.mPath        = aEventOptions.mPath;
     456         662 :     opts.mFabricIndex = aEventOptions.mFabricIndex;
     457             : 
     458         662 :     ctxt.mCurrentEventNumber = mLastEventNumber;
     459         662 :     ctxt.mCurrentTime.mValue = mLastEventTimestamp.mValue;
     460             : 
     461         662 :     err = CalculateEventSize(apDelegate, &opts, requestSize);
     462         662 :     SuccessOrExit(err);
     463             : 
     464             :     // Ensure we have space in the in-memory logging queues
     465         662 :     err = EnsureSpaceInCircularBuffer(requestSize, aEventOptions.mPriority);
     466         662 :     SuccessOrExit(err);
     467             : 
     468         662 :     err = ConstructEvent(&ctxt, apDelegate, &opts);
     469         662 :     SuccessOrExit(err);
     470             : 
     471         662 :     mBytesWritten += writer.GetLengthWritten();
     472             : 
     473         662 : exit:
     474         662 :     if (err != CHIP_NO_ERROR)
     475             :     {
     476           0 :         ChipLogError(EventLogging, "Log event with error %" CHIP_ERROR_FORMAT, err.Format());
     477           0 :         writer = checkpoint;
     478             :     }
     479             :     else if (opts.mPriority >= CHIP_CONFIG_EVENT_GLOBAL_PRIORITY)
     480             :     {
     481         662 :         aEventNumber = mLastEventNumber;
     482         662 :         VendEventNumber();
     483         662 :         mLastEventTimestamp = timestamp;
     484             : #if CHIP_CONFIG_EVENT_LOGGING_VERBOSE_DEBUG_LOGS
     485         662 :         ChipLogDetail(EventLogging,
     486             :                       "LogEvent event number: 0x" ChipLogFormatX64 " priority: %u, endpoint id:  0x%x"
     487             :                       " cluster id: " ChipLogFormatMEI " event id: 0x%" PRIx32 " %s timestamp: 0x" ChipLogFormatX64,
     488             :                       ChipLogValueX64(aEventNumber), static_cast<unsigned>(opts.mPriority), opts.mPath.mEndpointId,
     489             :                       ChipLogValueMEI(opts.mPath.mClusterId), opts.mPath.mEventId,
     490             :                       opts.mTimestamp.mType == Timestamp::Type::kSystem ? "Sys" : "Epoch", ChipLogValueX64(opts.mTimestamp.mValue));
     491             : #endif // CHIP_CONFIG_EVENT_LOGGING_VERBOSE_DEBUG_LOGS
     492             : 
     493         662 :         err = InteractionModelEngine::GetInstance()->GetReportingEngine().ScheduleEventDelivery(opts.mPath, mBytesWritten);
     494             :     }
     495             : 
     496         662 :     return err;
     497             : }
     498             : 
     499        2163 : CHIP_ERROR EventManagement::CopyEvent(const TLVReader & aReader, TLVWriter & aWriter, EventLoadOutContext * apContext)
     500             : {
     501             :     TLVReader reader;
     502             :     TLVType containerType;
     503             :     TLVType containerType1;
     504        2163 :     CopyAndAdjustDeltaTimeContext context(&aWriter, apContext);
     505        2163 :     CHIP_ERROR err = CHIP_NO_ERROR;
     506             : 
     507        2163 :     reader.Init(aReader);
     508        2163 :     ReturnErrorOnFailure(reader.EnterContainer(containerType));
     509        2163 :     ReturnErrorOnFailure(aWriter.StartContainer(AnonymousTag(), kTLVType_Structure, containerType));
     510             : 
     511        2149 :     ReturnErrorOnFailure(reader.Next());
     512        2149 :     ReturnErrorOnFailure(reader.EnterContainer(containerType1));
     513        2149 :     ReturnErrorOnFailure(
     514             :         aWriter.StartContainer(TLV::ContextTag(EventReportIB::Tag::kEventData), kTLVType_Structure, containerType1));
     515        2119 :     err = TLV::Utilities::Iterate(reader, CopyAndAdjustDeltaTime, &context, false /*recurse*/);
     516        2119 :     if (err == CHIP_END_OF_TLV)
     517             :     {
     518        1657 :         err = CHIP_NO_ERROR;
     519             :     }
     520        2119 :     ReturnErrorOnFailure(err);
     521        1657 :     ReturnErrorOnFailure(aWriter.EndContainer(containerType1));
     522        1652 :     ReturnErrorOnFailure(aWriter.EndContainer(containerType));
     523        1648 :     ReturnErrorOnFailure(aWriter.Finalize());
     524        1648 :     return CHIP_NO_ERROR;
     525             : }
     526             : 
     527        3248 : CHIP_ERROR EventManagement::CheckEventContext(EventLoadOutContext * eventLoadOutContext,
     528             :                                               const EventManagement::EventEnvelopeContext & event)
     529             : {
     530        3248 :     if (eventLoadOutContext->mCurrentEventNumber < eventLoadOutContext->mStartingEventNumber)
     531             :     {
     532        1032 :         return CHIP_ERROR_UNEXPECTED_EVENT;
     533             :     }
     534             : 
     535        2251 :     if (event.mFabricIndex.HasValue() &&
     536          35 :         (event.mFabricIndex.Value() == kUndefinedFabricIndex ||
     537          28 :          eventLoadOutContext->mSubjectDescriptor.fabricIndex != event.mFabricIndex.Value()))
     538             :     {
     539          22 :         return CHIP_ERROR_UNEXPECTED_EVENT;
     540             :     }
     541             : 
     542        2194 :     ConcreteEventPath path(event.mEndpointId, event.mClusterId, event.mEventId);
     543        2194 :     CHIP_ERROR ret = CHIP_ERROR_UNEXPECTED_EVENT;
     544             : 
     545        2242 :     for (auto * interestedPath = eventLoadOutContext->mpInterestedEventPaths; interestedPath != nullptr;
     546          48 :          interestedPath        = interestedPath->mpNext)
     547             :     {
     548        2217 :         if (interestedPath->mValue.IsEventPathSupersetOf(path))
     549             :         {
     550        2169 :             ret = CHIP_NO_ERROR;
     551        2169 :             break;
     552             :         }
     553             :     }
     554             : 
     555        2194 :     ReturnErrorOnFailure(ret);
     556             : 
     557        2169 :     Access::RequestPath requestPath{ .cluster = event.mClusterId, .endpoint = event.mEndpointId };
     558        2169 :     Access::Privilege requestPrivilege = RequiredPrivilege::ForReadEvent(path);
     559             :     CHIP_ERROR accessControlError =
     560        2169 :         Access::GetAccessControl().Check(eventLoadOutContext->mSubjectDescriptor, requestPath, requestPrivilege);
     561        2169 :     if (accessControlError != CHIP_NO_ERROR)
     562             :     {
     563           6 :         ReturnErrorCodeIf(accessControlError != CHIP_ERROR_ACCESS_DENIED, accessControlError);
     564           6 :         ret = CHIP_ERROR_UNEXPECTED_EVENT;
     565             :     }
     566             : 
     567        2169 :     return ret;
     568             : }
     569             : 
     570        3248 : CHIP_ERROR EventManagement::EventIterator(const TLVReader & aReader, size_t aDepth, EventLoadOutContext * apEventLoadOutContext,
     571             :                                           EventEnvelopeContext * event)
     572             : {
     573        3248 :     CHIP_ERROR err = CHIP_NO_ERROR;
     574             :     TLVReader innerReader;
     575             :     TLVType tlvType;
     576             :     TLVType tlvType1;
     577             : 
     578        3248 :     innerReader.Init(aReader);
     579        3248 :     VerifyOrDie(event != nullptr);
     580        3248 :     ReturnErrorOnFailure(innerReader.EnterContainer(tlvType));
     581        3248 :     ReturnErrorOnFailure(innerReader.Next());
     582             : 
     583        3248 :     ReturnErrorOnFailure(innerReader.EnterContainer(tlvType1));
     584        3248 :     err = TLV::Utilities::Iterate(innerReader, FetchEventParameters, event, false /*recurse*/);
     585             : 
     586        3248 :     if (event->mFieldsToRead != kRequiredEventField)
     587             :     {
     588           0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     589             :     }
     590             : 
     591        3248 :     if (err == CHIP_END_OF_TLV)
     592             :     {
     593        3248 :         err = CHIP_NO_ERROR;
     594             :     }
     595        3248 :     ReturnErrorOnFailure(err);
     596             : 
     597        3248 :     apEventLoadOutContext->mCurrentTime        = event->mCurrentTime;
     598        3248 :     apEventLoadOutContext->mCurrentEventNumber = event->mEventNumber;
     599             : 
     600        3248 :     err = CheckEventContext(apEventLoadOutContext, *event);
     601        3248 :     if (err == CHIP_NO_ERROR)
     602             :     {
     603        2163 :         err = CHIP_EVENT_ID_FOUND;
     604             :     }
     605        1085 :     else if (err == CHIP_ERROR_UNEXPECTED_EVENT)
     606             :     {
     607        1085 :         err = CHIP_NO_ERROR;
     608             :     }
     609             : 
     610        3248 :     return err;
     611             : }
     612             : 
     613        3248 : CHIP_ERROR EventManagement::CopyEventsSince(const TLVReader & aReader, size_t aDepth, void * apContext)
     614             : {
     615        3248 :     EventLoadOutContext * const loadOutContext = static_cast<EventLoadOutContext *>(apContext);
     616        3248 :     EventEnvelopeContext event;
     617        3248 :     CHIP_ERROR err = EventIterator(aReader, aDepth, loadOutContext, &event);
     618        3248 :     if (err == CHIP_EVENT_ID_FOUND)
     619             :     {
     620             :         // checkpoint the writer
     621        2163 :         TLV::TLVWriter checkpoint = loadOutContext->mWriter;
     622             : 
     623        2163 :         err = CopyEvent(aReader, loadOutContext->mWriter, loadOutContext);
     624             : 
     625             :         // CHIP_NO_ERROR and CHIP_END_OF_TLV signify a
     626             :         // successful copy.  In all other cases, roll back the
     627             :         // writer state back to the checkpoint, i.e., the state
     628             :         // before we began the copy operation.
     629        2163 :         if ((err != CHIP_NO_ERROR) && (err != CHIP_END_OF_TLV))
     630             :         {
     631         515 :             loadOutContext->mWriter = checkpoint;
     632         515 :             return err;
     633             :         }
     634             : 
     635        1648 :         loadOutContext->mPreviousTime.mValue = loadOutContext->mCurrentTime.mValue;
     636        1648 :         loadOutContext->mFirst               = false;
     637        1648 :         loadOutContext->mEventCount++;
     638             :     }
     639        2733 :     return err;
     640        3248 : }
     641             : 
     642         892 : CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, const ObjectList<EventPathParams> * apEventPathList,
     643             :                                              EventNumber & aEventMin, size_t & aEventCount,
     644             :                                              const Access::SubjectDescriptor & aSubjectDescriptor)
     645             : {
     646             :     // TODO: Add particular set of event Paths in FetchEventsSince so that we can filter the interested paths
     647         892 :     CHIP_ERROR err     = CHIP_NO_ERROR;
     648         892 :     const bool recurse = false;
     649             :     TLVReader reader;
     650         892 :     CircularEventBufferWrapper bufWrapper;
     651         892 :     EventLoadOutContext context(aWriter, PriorityLevel::Invalid, aEventMin);
     652             : 
     653         892 :     context.mSubjectDescriptor     = aSubjectDescriptor;
     654         892 :     context.mpInterestedEventPaths = apEventPathList;
     655         892 :     err                            = GetEventReader(reader, PriorityLevel::Critical, &bufWrapper);
     656         892 :     SuccessOrExit(err);
     657             : 
     658         892 :     err = TLV::Utilities::Iterate(reader, CopyEventsSince, &context, recurse);
     659         892 :     if (err == CHIP_END_OF_TLV)
     660             :     {
     661         377 :         err = CHIP_NO_ERROR;
     662             :     }
     663             : 
     664         515 : exit:
     665         892 :     if (err == CHIP_ERROR_BUFFER_TOO_SMALL || err == CHIP_ERROR_NO_MEMORY)
     666             :     {
     667             :         // We failed to fetch the current event because the buffer is too small, we will start from this one the next time.
     668         515 :         aEventMin = context.mCurrentEventNumber;
     669             :     }
     670             :     else
     671             :     {
     672             :         // For all other cases, continue from the next event.
     673         377 :         aEventMin = context.mCurrentEventNumber + 1;
     674             :     }
     675         892 :     aEventCount += context.mEventCount;
     676         892 :     return err;
     677         892 : }
     678             : 
     679           8 : CHIP_ERROR EventManagement::FabricRemovedCB(const TLV::TLVReader & aReader, size_t aDepth, void * apContext)
     680             : {
     681             :     // the function does not actually remove the event, instead, it sets the fabric index to an invalid value.
     682           8 :     FabricIndex * invalidFabricIndex = static_cast<FabricIndex *>(apContext);
     683             : 
     684             :     TLVReader event;
     685             :     TLVType tlvType;
     686             :     TLVType tlvType1;
     687           8 :     event.Init(aReader);
     688           8 :     VerifyOrReturnError(event.EnterContainer(tlvType) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     689           8 :     VerifyOrReturnError(event.Next(TLV::ContextTag(EventReportIB::Tag::kEventData)) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     690           8 :     VerifyOrReturnError(event.EnterContainer(tlvType1) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     691             : 
     692          48 :     while (CHIP_NO_ERROR == event.Next())
     693             :     {
     694          48 :         if (event.GetTag() == TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag))
     695             :         {
     696           8 :             uint8_t fabricIndex = 0;
     697           8 :             VerifyOrReturnError(event.Get(fabricIndex) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     698           8 :             if (fabricIndex == *invalidFabricIndex)
     699             :             {
     700           4 :                 TLVCircularBuffer * readBuffer = static_cast<TLVCircularBuffer *>(event.GetBackingStore());
     701             :                 // fabricIndex is encoded as an integer; the dataPtr will point to a location immediately after its encoding
     702             :                 // shift the dataPtr to point to the encoding of the fabric index, accounting for wraparound in backing storage
     703             :                 // we cannot get the actual encoding size from current container beginning to the fabric index because of several
     704             :                 // optional parameters, so we are assuming minimal encoding is used and the fabric index is 1 byte.
     705             :                 uint8_t * dataPtr;
     706           4 :                 if (event.GetReadPoint() != readBuffer->GetQueue())
     707             :                 {
     708           4 :                     dataPtr = readBuffer->GetQueue() + (event.GetReadPoint() - readBuffer->GetQueue() - 1);
     709             :                 }
     710             :                 else
     711             :                 {
     712           0 :                     dataPtr = readBuffer->GetQueue() + readBuffer->GetTotalDataLength() - 1;
     713             :                 }
     714             : 
     715           4 :                 *dataPtr = kUndefinedFabricIndex;
     716             :             }
     717           8 :             return CHIP_NO_ERROR;
     718             :         }
     719             :     }
     720           0 :     return CHIP_NO_ERROR;
     721             : }
     722             : 
     723           2 : CHIP_ERROR EventManagement::FabricRemoved(FabricIndex aFabricIndex)
     724             : {
     725           2 :     const bool recurse = false;
     726             :     TLVReader reader;
     727           2 :     CircularEventBufferWrapper bufWrapper;
     728             : 
     729           2 :     ReturnErrorOnFailure(GetEventReader(reader, PriorityLevel::Critical, &bufWrapper));
     730           2 :     CHIP_ERROR err = TLV::Utilities::Iterate(reader, FabricRemovedCB, &aFabricIndex, recurse);
     731           2 :     if (err == CHIP_END_OF_TLV)
     732             :     {
     733           2 :         err = CHIP_NO_ERROR;
     734             :     }
     735           2 :     return err;
     736           2 : }
     737             : 
     738         943 : CHIP_ERROR EventManagement::GetEventReader(TLVReader & aReader, PriorityLevel aPriority, CircularEventBufferWrapper * apBufWrapper)
     739             : {
     740         943 :     CircularEventBuffer * buffer = GetPriorityBuffer(aPriority);
     741         943 :     VerifyOrReturnError(buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     742         943 :     apBufWrapper->mpCurrent = buffer;
     743             : 
     744         943 :     CircularEventReader reader;
     745         943 :     reader.Init(apBufWrapper);
     746         943 :     aReader.Init(reader);
     747             : 
     748         943 :     return CHIP_NO_ERROR;
     749         943 : }
     750             : 
     751       21786 : CHIP_ERROR EventManagement::FetchEventParameters(const TLVReader & aReader, size_t, void * apContext)
     752             : {
     753       21786 :     EventEnvelopeContext * const envelope = static_cast<EventEnvelopeContext *>(apContext);
     754             :     TLVReader reader;
     755       21786 :     reader.Init(aReader);
     756             : 
     757       21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kPath))
     758             :     {
     759        4348 :         EventPathIB::Parser path;
     760        4348 :         ReturnErrorOnFailure(path.Init(aReader));
     761        4348 :         ReturnErrorOnFailure(path.GetEndpoint(&(envelope->mEndpointId)));
     762        4348 :         ReturnErrorOnFailure(path.GetCluster(&(envelope->mClusterId)));
     763        4348 :         ReturnErrorOnFailure(path.GetEvent(&(envelope->mEventId)));
     764        4348 :         envelope->mFieldsToRead |= 1 << to_underlying(EventDataIB::Tag::kPath);
     765             :     }
     766             : 
     767       21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kPriority))
     768             :     {
     769             :         uint16_t extPriority; // Note: the type here matches the type case in EventManagement::LogEvent, priority section
     770        4348 :         ReturnErrorOnFailure(reader.Get(extPriority));
     771        4348 :         envelope->mPriority = static_cast<PriorityLevel>(extPriority);
     772        4348 :         envelope->mFieldsToRead |= 1 << to_underlying(EventDataIB::Tag::kPriority);
     773             :     }
     774             : 
     775       21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kEventNumber))
     776             :     {
     777        4348 :         ReturnErrorOnFailure(reader.Get(envelope->mEventNumber));
     778             :     }
     779             : 
     780       21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kSystemTimestamp))
     781             :     {
     782             :         uint64_t systemTime;
     783          58 :         ReturnErrorOnFailure(reader.Get(systemTime));
     784          58 :         envelope->mCurrentTime.mType  = Timestamp::Type::kSystem;
     785          58 :         envelope->mCurrentTime.mValue = systemTime;
     786             :     }
     787             : 
     788       21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kEpochTimestamp))
     789             :     {
     790             :         uint64_t epochTime;
     791        4290 :         ReturnErrorOnFailure(reader.Get(epochTime));
     792        4290 :         envelope->mCurrentTime.mType  = Timestamp::Type::kEpoch;
     793        4290 :         envelope->mCurrentTime.mValue = epochTime;
     794             :     }
     795             : 
     796       21786 :     if (reader.GetTag() == TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag))
     797             :     {
     798          46 :         uint8_t fabricIndex = kUndefinedFabricIndex;
     799          46 :         ReturnErrorOnFailure(reader.Get(fabricIndex));
     800          46 :         envelope->mFabricIndex.SetValue(fabricIndex);
     801             :     }
     802       21786 :     return CHIP_NO_ERROR;
     803             : }
     804             : 
     805        1100 : CHIP_ERROR EventManagement::EvictEvent(TLVCircularBuffer & apBuffer, void * apAppData, TLVReader & aReader)
     806             : {
     807             :     // pull out the delta time, pull out the priority
     808        1100 :     ReturnErrorOnFailure(aReader.Next());
     809             : 
     810             :     TLVType containerType;
     811             :     TLVType containerType1;
     812        1100 :     ReturnErrorOnFailure(aReader.EnterContainer(containerType));
     813        1100 :     ReturnErrorOnFailure(aReader.Next());
     814             : 
     815        1100 :     ReturnErrorOnFailure(aReader.EnterContainer(containerType1));
     816        1100 :     EventEnvelopeContext context;
     817        1100 :     constexpr bool recurse = false;
     818        1100 :     CHIP_ERROR err         = TLV::Utilities::Iterate(aReader, FetchEventParameters, &context, recurse);
     819        1100 :     if (err == CHIP_END_OF_TLV)
     820             :     {
     821        1100 :         err = CHIP_NO_ERROR;
     822             :     }
     823        1100 :     ReturnErrorOnFailure(err);
     824             : 
     825        1100 :     ReturnErrorOnFailure(aReader.ExitContainer(containerType1));
     826        1100 :     ReturnErrorOnFailure(aReader.ExitContainer(containerType));
     827        1100 :     const PriorityLevel imp = static_cast<PriorityLevel>(context.mPriority);
     828             : 
     829        1100 :     ReclaimEventCtx * const ctx             = static_cast<ReclaimEventCtx *>(apAppData);
     830        1100 :     CircularEventBuffer * const eventBuffer = ctx->mpEventBuffer;
     831        1100 :     if (eventBuffer->IsFinalDestinationForPriority(imp))
     832             :     {
     833         365 :         ChipLogProgress(EventLogging,
     834             :                         "Dropped 1 event from buffer with priority %u and event number  0x" ChipLogFormatX64
     835             :                         " due to overflow: event priority_level: %u",
     836             :                         static_cast<unsigned>(eventBuffer->GetPriority()), ChipLogValueX64(context.mEventNumber),
     837             :                         static_cast<unsigned>(imp));
     838         365 :         ctx->mSpaceNeededForMovedEvent = 0;
     839         365 :         return CHIP_NO_ERROR;
     840             :     }
     841             : 
     842             :     // event is not getting dropped. Note how much space it requires, and return.
     843         735 :     ctx->mSpaceNeededForMovedEvent = aReader.GetLengthRead();
     844         735 :     return CHIP_END_OF_TLV;
     845        1100 : }
     846             : 
     847         344 : void EventManagement::SetScheduledEventInfo(EventNumber & aEventNumber, uint32_t & aInitialWrittenEventBytes) const
     848             : {
     849         344 :     aEventNumber              = mLastEventNumber;
     850         344 :     aInitialWrittenEventBytes = mBytesWritten;
     851         344 : }
     852             : 
     853         369 : void CircularEventBuffer::Init(uint8_t * apBuffer, uint32_t aBufferLength, CircularEventBuffer * apPrev,
     854             :                                CircularEventBuffer * apNext, PriorityLevel aPriorityLevel)
     855             : {
     856         369 :     TLVCircularBuffer::Init(apBuffer, aBufferLength);
     857         369 :     mpPrev    = apPrev;
     858         369 :     mpNext    = apNext;
     859         369 :     mPriority = aPriorityLevel;
     860         369 : }
     861             : 
     862        5223 : bool CircularEventBuffer::IsFinalDestinationForPriority(PriorityLevel aPriority) const
     863             : {
     864        5223 :     return !((mpNext != nullptr) && (mpNext->mPriority <= aPriority));
     865             : }
     866             : 
     867             : /**
     868             :  * @brief
     869             :  * TLVCircularBuffer::OnInit can modify the state of the buffer, but we don't want that behavior here.
     870             :  * We want to make sure we don't change our state, and just report the currently-available space.
     871             :  */
     872        1084 : CHIP_ERROR CircularEventBuffer::OnInit(TLV::TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen)
     873             : {
     874        1084 :     GetCurrentWritableBuffer(bufStart, bufLen);
     875        1084 :     return CHIP_NO_ERROR;
     876             : }
     877             : 
     878         943 : void CircularEventReader::Init(CircularEventBufferWrapper * apBufWrapper)
     879             : {
     880             :     CircularEventBuffer * prev;
     881             : 
     882         943 :     if (apBufWrapper->mpCurrent == nullptr)
     883           0 :         return;
     884             : 
     885         943 :     TLVReader::Init(*apBufWrapper, apBufWrapper->mpCurrent->DataLength());
     886         943 :     mMaxLen = apBufWrapper->mpCurrent->DataLength();
     887         991 :     for (prev = apBufWrapper->mpCurrent->GetPreviousCircularEventBuffer(); prev != nullptr;
     888          48 :          prev = prev->GetPreviousCircularEventBuffer())
     889             :     {
     890          48 :         CircularEventBufferWrapper bufWrapper;
     891          48 :         bufWrapper.mpCurrent = prev;
     892          48 :         mMaxLen += prev->DataLength();
     893          48 :     }
     894             : }
     895             : 
     896        2933 : CHIP_ERROR CircularEventBufferWrapper::GetNextBuffer(TLVReader & aReader, const uint8_t *& aBufStart, uint32_t & aBufLen)
     897             : {
     898        2933 :     CHIP_ERROR err = CHIP_NO_ERROR;
     899        2933 :     mpCurrent->GetNextBuffer(aReader, aBufStart, aBufLen);
     900        2933 :     SuccessOrExit(err);
     901             : 
     902        2933 :     if ((aBufLen == 0) && (mpCurrent->GetPreviousCircularEventBuffer() != nullptr))
     903             :     {
     904        1814 :         mpCurrent = mpCurrent->GetPreviousCircularEventBuffer();
     905        1814 :         aBufStart = nullptr;
     906        1814 :         err       = GetNextBuffer(aReader, aBufStart, aBufLen);
     907             :     }
     908             : 
     909        1119 : exit:
     910        2933 :     return err;
     911             : }
     912             : } // namespace app
     913             : } // namespace chip

Generated by: LCOV version 1.14