Matter SDK Coverage Report
Current view: top level - app - EventManagement.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 96.6 % 437 422
Test Date: 2025-02-22 08:08:07 Functions: 93.9 % 33 31

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

Generated by: LCOV version 2.0-1