Matter SDK Coverage Report
Current view: top level - app - EventManagement.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 95.7 % 439 420
Test Date: 2025-01-17 19:00:11 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         2239 : EventManagement & EventManagement::GetInstance()
      61              : {
      62         2239 :     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 : 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          125 :     CircularEventBuffer * current = nullptr;
      89          125 :     CircularEventBuffer * prev    = nullptr;
      90          125 :     CircularEventBuffer * next    = nullptr;
      91              : 
      92          125 :     if (aNumBuffers == 0)
      93              :     {
      94            0 :         ChipLogError(EventLogging, "Invalid aNumBuffers");
      95            0 :         return;
      96              :     }
      97              : 
      98          125 :     if (mState != EventManagementStates::Shutdown)
      99              :     {
     100            0 :         ChipLogError(EventLogging, "Invalid EventManagement State");
     101            0 :         return;
     102              :     }
     103          125 :     mpExchangeMgr = apExchangeManager;
     104              : 
     105          500 :     for (uint32_t bufferIndex = 0; bufferIndex < aNumBuffers; bufferIndex++)
     106              :     {
     107          375 :         next = (bufferIndex < aNumBuffers - 1) ? &apCircularEventBuffer[bufferIndex + 1] : nullptr;
     108              : 
     109          375 :         current = &apCircularEventBuffer[bufferIndex];
     110          375 :         current->Init(apLogStorageResources[bufferIndex].mpBuffer, apLogStorageResources[bufferIndex].mBufferSize, prev, next,
     111          375 :                       apLogStorageResources[bufferIndex].mPriority);
     112              : 
     113          375 :         prev = current;
     114              : 
     115          375 :         current->mProcessEvictedElement = nullptr;
     116          375 :         current->mAppData               = nullptr;
     117              :     }
     118              : 
     119          125 :     mpEventNumberCounter = apEventNumberCounter;
     120          125 :     mLastEventNumber     = mpEventNumberCounter->GetValue();
     121              : 
     122          125 :     mpEventBuffer = apCircularEventBuffer;
     123          125 :     mState        = EventManagementStates::Idle;
     124          125 :     mBytesWritten = 0;
     125              : 
     126          125 :     mMonotonicStartupTime = aMonotonicStartupTime;
     127              : }
     128              : 
     129          422 : CHIP_ERROR EventManagement::CopyToNextBuffer(CircularEventBuffer * apEventBuffer)
     130              : {
     131          422 :     CircularTLVWriter writer;
     132          422 :     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          124 : 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          124 :     sInstance.Init(apExchangeManager, aNumBuffers, apCircularEventBuffer, apLogStorageResources, apEventNumberCounter,
     348              :                    aMonotonicStartupTime);
     349          124 : }
     350              : 
     351              : /**
     352              :  * @brief Perform any actions we need to on shutdown.
     353              :  */
     354          124 : void EventManagement::DestroyEventManagement()
     355              : {
     356          124 :     sInstance.mState        = EventManagementStates::Shutdown;
     357          124 :     sInstance.mpEventBuffer = nullptr;
     358          124 :     sInstance.mpExchangeMgr = nullptr;
     359          124 : }
     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         2163 :     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,
     558         2169 :                                      .endpoint    = event.mEndpointId,
     559              :                                      .requestType = Access::RequestType::kEventReadRequest,
     560         2169 :                                      .entityId    = event.mEventId };
     561         2169 :     Access::Privilege requestPrivilege = RequiredPrivilege::ForReadEvent(path);
     562              :     CHIP_ERROR accessControlError =
     563         2169 :         Access::GetAccessControl().Check(eventLoadOutContext->mSubjectDescriptor, requestPath, requestPrivilege);
     564         2169 :     if (accessControlError != CHIP_NO_ERROR)
     565              :     {
     566            6 :         VerifyOrReturnError((accessControlError == CHIP_ERROR_ACCESS_DENIED) ||
     567              :                                 (accessControlError == CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL),
     568              :                             accessControlError);
     569            6 :         ret = CHIP_ERROR_UNEXPECTED_EVENT;
     570              :     }
     571              : 
     572         2169 :     return ret;
     573              : }
     574              : 
     575         3248 : CHIP_ERROR EventManagement::EventIterator(const TLVReader & aReader, size_t aDepth, EventLoadOutContext * apEventLoadOutContext,
     576              :                                           EventEnvelopeContext * event)
     577              : {
     578         3248 :     CHIP_ERROR err = CHIP_NO_ERROR;
     579         3248 :     TLVReader innerReader;
     580              :     TLVType tlvType;
     581              :     TLVType tlvType1;
     582              : 
     583         3248 :     innerReader.Init(aReader);
     584         3248 :     VerifyOrDie(event != nullptr);
     585         3248 :     ReturnErrorOnFailure(innerReader.EnterContainer(tlvType));
     586         3248 :     ReturnErrorOnFailure(innerReader.Next());
     587              : 
     588         3248 :     ReturnErrorOnFailure(innerReader.EnterContainer(tlvType1));
     589         3248 :     err = TLV::Utilities::Iterate(innerReader, FetchEventParameters, event, false /*recurse*/);
     590              : 
     591         3248 :     if (event->mFieldsToRead != kRequiredEventField)
     592              :     {
     593            0 :         return CHIP_ERROR_INVALID_ARGUMENT;
     594              :     }
     595              : 
     596         3248 :     if (err == CHIP_END_OF_TLV)
     597              :     {
     598         3248 :         err = CHIP_NO_ERROR;
     599              :     }
     600         3248 :     ReturnErrorOnFailure(err);
     601              : 
     602         3248 :     apEventLoadOutContext->mCurrentTime        = event->mCurrentTime;
     603         3248 :     apEventLoadOutContext->mCurrentEventNumber = event->mEventNumber;
     604              : 
     605         3248 :     err = CheckEventContext(apEventLoadOutContext, *event);
     606         3248 :     if (err == CHIP_NO_ERROR)
     607              :     {
     608         2163 :         err = CHIP_EVENT_ID_FOUND;
     609              :     }
     610         1085 :     else if (err == CHIP_ERROR_UNEXPECTED_EVENT)
     611              :     {
     612         1085 :         err = CHIP_NO_ERROR;
     613              :     }
     614              : 
     615         3248 :     return err;
     616              : }
     617              : 
     618         3248 : CHIP_ERROR EventManagement::CopyEventsSince(const TLVReader & aReader, size_t aDepth, void * apContext)
     619              : {
     620         3248 :     EventLoadOutContext * const loadOutContext = static_cast<EventLoadOutContext *>(apContext);
     621         3248 :     EventEnvelopeContext event;
     622         3248 :     CHIP_ERROR err = EventIterator(aReader, aDepth, loadOutContext, &event);
     623         3248 :     if (err == CHIP_EVENT_ID_FOUND)
     624              :     {
     625              :         // checkpoint the writer
     626         2163 :         TLV::TLVWriter checkpoint = loadOutContext->mWriter;
     627              : 
     628         2163 :         err = CopyEvent(aReader, loadOutContext->mWriter, loadOutContext);
     629              : 
     630              :         // CHIP_NO_ERROR and CHIP_END_OF_TLV signify a
     631              :         // successful copy.  In all other cases, roll back the
     632              :         // writer state back to the checkpoint, i.e., the state
     633              :         // before we began the copy operation.
     634         2163 :         if ((err != CHIP_NO_ERROR) && (err != CHIP_END_OF_TLV))
     635              :         {
     636          515 :             loadOutContext->mWriter = checkpoint;
     637          515 :             return err;
     638              :         }
     639              : 
     640         1648 :         loadOutContext->mPreviousTime.mValue = loadOutContext->mCurrentTime.mValue;
     641         1648 :         loadOutContext->mFirst               = false;
     642         1648 :         loadOutContext->mEventCount++;
     643              :     }
     644         2733 :     return err;
     645         3248 : }
     646              : 
     647          892 : CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, const SingleLinkedListNode<EventPathParams> * apEventPathList,
     648              :                                              EventNumber & aEventMin, size_t & aEventCount,
     649              :                                              const Access::SubjectDescriptor & aSubjectDescriptor)
     650              : {
     651              :     // TODO: Add particular set of event Paths in FetchEventsSince so that we can filter the interested paths
     652          892 :     CHIP_ERROR err     = CHIP_NO_ERROR;
     653          892 :     const bool recurse = false;
     654          892 :     TLVReader reader;
     655          892 :     CircularEventBufferWrapper bufWrapper;
     656          892 :     EventLoadOutContext context(aWriter, PriorityLevel::Invalid, aEventMin);
     657              : 
     658          892 :     context.mSubjectDescriptor     = aSubjectDescriptor;
     659          892 :     context.mpInterestedEventPaths = apEventPathList;
     660          892 :     err                            = GetEventReader(reader, PriorityLevel::Critical, &bufWrapper);
     661          892 :     SuccessOrExit(err);
     662              : 
     663          892 :     err = TLV::Utilities::Iterate(reader, CopyEventsSince, &context, recurse);
     664          892 :     if (err == CHIP_END_OF_TLV)
     665              :     {
     666          377 :         err = CHIP_NO_ERROR;
     667              :     }
     668              : 
     669          515 : exit:
     670          892 :     if (err == CHIP_ERROR_BUFFER_TOO_SMALL || err == CHIP_ERROR_NO_MEMORY)
     671              :     {
     672              :         // We failed to fetch the current event because the buffer is too small, we will start from this one the next time.
     673          515 :         aEventMin = context.mCurrentEventNumber;
     674              :     }
     675              :     else
     676              :     {
     677              :         // For all other cases, continue from the next event.
     678          377 :         aEventMin = context.mCurrentEventNumber + 1;
     679              :     }
     680          892 :     aEventCount += context.mEventCount;
     681          892 :     return err;
     682          892 : }
     683              : 
     684            8 : CHIP_ERROR EventManagement::FabricRemovedCB(const TLV::TLVReader & aReader, size_t aDepth, void * apContext)
     685              : {
     686              :     // the function does not actually remove the event, instead, it sets the fabric index to an invalid value.
     687            8 :     FabricIndex * invalidFabricIndex = static_cast<FabricIndex *>(apContext);
     688              : 
     689            8 :     TLVReader event;
     690              :     TLVType tlvType;
     691              :     TLVType tlvType1;
     692            8 :     event.Init(aReader);
     693            8 :     VerifyOrReturnError(event.EnterContainer(tlvType) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     694            8 :     VerifyOrReturnError(event.Next(TLV::ContextTag(EventReportIB::Tag::kEventData)) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     695            8 :     VerifyOrReturnError(event.EnterContainer(tlvType1) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     696              : 
     697           48 :     while (CHIP_NO_ERROR == event.Next())
     698              :     {
     699           48 :         if (event.GetTag() == TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag))
     700              :         {
     701            8 :             uint8_t fabricIndex = 0;
     702            8 :             VerifyOrReturnError(event.Get(fabricIndex) == CHIP_NO_ERROR, CHIP_NO_ERROR);
     703            8 :             if (fabricIndex == *invalidFabricIndex)
     704              :             {
     705            4 :                 TLVCircularBuffer * readBuffer = static_cast<TLVCircularBuffer *>(event.GetBackingStore());
     706              :                 // fabricIndex is encoded as an integer; the dataPtr will point to a location immediately after its encoding
     707              :                 // shift the dataPtr to point to the encoding of the fabric index, accounting for wraparound in backing storage
     708              :                 // we cannot get the actual encoding size from current container beginning to the fabric index because of several
     709              :                 // optional parameters, so we are assuming minimal encoding is used and the fabric index is 1 byte.
     710              :                 uint8_t * dataPtr;
     711            4 :                 if (event.GetReadPoint() != readBuffer->GetQueue())
     712              :                 {
     713            4 :                     dataPtr = readBuffer->GetQueue() + (event.GetReadPoint() - readBuffer->GetQueue() - 1);
     714              :                 }
     715              :                 else
     716              :                 {
     717            0 :                     dataPtr = readBuffer->GetQueue() + readBuffer->GetTotalDataLength() - 1;
     718              :                 }
     719              : 
     720            4 :                 *dataPtr = kUndefinedFabricIndex;
     721              :             }
     722            8 :             return CHIP_NO_ERROR;
     723              :         }
     724              :     }
     725            0 :     return CHIP_NO_ERROR;
     726              : }
     727              : 
     728            2 : CHIP_ERROR EventManagement::FabricRemoved(FabricIndex aFabricIndex)
     729              : {
     730            2 :     const bool recurse = false;
     731            2 :     TLVReader reader;
     732            2 :     CircularEventBufferWrapper bufWrapper;
     733              : 
     734            2 :     ReturnErrorOnFailure(GetEventReader(reader, PriorityLevel::Critical, &bufWrapper));
     735            2 :     CHIP_ERROR err = TLV::Utilities::Iterate(reader, FabricRemovedCB, &aFabricIndex, recurse);
     736            2 :     if (err == CHIP_END_OF_TLV)
     737              :     {
     738            2 :         err = CHIP_NO_ERROR;
     739              :     }
     740            2 :     return err;
     741            2 : }
     742              : 
     743          943 : CHIP_ERROR EventManagement::GetEventReader(TLVReader & aReader, PriorityLevel aPriority, CircularEventBufferWrapper * apBufWrapper)
     744              : {
     745          943 :     CircularEventBuffer * buffer = GetPriorityBuffer(aPriority);
     746          943 :     VerifyOrReturnError(buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     747          943 :     apBufWrapper->mpCurrent = buffer;
     748              : 
     749          943 :     CircularEventReader reader;
     750          943 :     reader.Init(apBufWrapper);
     751          943 :     aReader.Init(reader);
     752              : 
     753          943 :     return CHIP_NO_ERROR;
     754          943 : }
     755              : 
     756        21786 : CHIP_ERROR EventManagement::FetchEventParameters(const TLVReader & aReader, size_t, void * apContext)
     757              : {
     758        21786 :     EventEnvelopeContext * const envelope = static_cast<EventEnvelopeContext *>(apContext);
     759        21786 :     TLVReader reader;
     760        21786 :     reader.Init(aReader);
     761              : 
     762        21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kPath))
     763              :     {
     764         4348 :         EventPathIB::Parser path;
     765         4348 :         ReturnErrorOnFailure(path.Init(aReader));
     766         4348 :         ReturnErrorOnFailure(path.GetEndpoint(&(envelope->mEndpointId)));
     767         4348 :         ReturnErrorOnFailure(path.GetCluster(&(envelope->mClusterId)));
     768         4348 :         ReturnErrorOnFailure(path.GetEvent(&(envelope->mEventId)));
     769         4348 :         envelope->mFieldsToRead |= 1 << to_underlying(EventDataIB::Tag::kPath);
     770              :     }
     771              : 
     772        21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kPriority))
     773              :     {
     774              :         uint16_t extPriority; // Note: the type here matches the type case in EventManagement::LogEvent, priority section
     775         4348 :         ReturnErrorOnFailure(reader.Get(extPriority));
     776         4348 :         envelope->mPriority = static_cast<PriorityLevel>(extPriority);
     777         4348 :         envelope->mFieldsToRead |= 1 << to_underlying(EventDataIB::Tag::kPriority);
     778              :     }
     779              : 
     780        21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kEventNumber))
     781              :     {
     782         4348 :         ReturnErrorOnFailure(reader.Get(envelope->mEventNumber));
     783              :     }
     784              : 
     785        21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kSystemTimestamp))
     786              :     {
     787              :         uint64_t systemTime;
     788           58 :         ReturnErrorOnFailure(reader.Get(systemTime));
     789           58 :         envelope->mCurrentTime.mType  = Timestamp::Type::kSystem;
     790           58 :         envelope->mCurrentTime.mValue = systemTime;
     791              :     }
     792              : 
     793        21786 :     if (reader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kEpochTimestamp))
     794              :     {
     795              :         uint64_t epochTime;
     796         4290 :         ReturnErrorOnFailure(reader.Get(epochTime));
     797         4290 :         envelope->mCurrentTime.mType  = Timestamp::Type::kEpoch;
     798         4290 :         envelope->mCurrentTime.mValue = epochTime;
     799              :     }
     800              : 
     801        21786 :     if (reader.GetTag() == TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag))
     802              :     {
     803           46 :         uint8_t fabricIndex = kUndefinedFabricIndex;
     804           46 :         ReturnErrorOnFailure(reader.Get(fabricIndex));
     805           46 :         envelope->mFabricIndex.SetValue(fabricIndex);
     806              :     }
     807        21786 :     return CHIP_NO_ERROR;
     808              : }
     809              : 
     810         1100 : CHIP_ERROR EventManagement::EvictEvent(TLVCircularBuffer & apBuffer, void * apAppData, TLVReader & aReader)
     811              : {
     812              :     // pull out the delta time, pull out the priority
     813         1100 :     ReturnErrorOnFailure(aReader.Next());
     814              : 
     815              :     TLVType containerType;
     816              :     TLVType containerType1;
     817         1100 :     ReturnErrorOnFailure(aReader.EnterContainer(containerType));
     818         1100 :     ReturnErrorOnFailure(aReader.Next());
     819              : 
     820         1100 :     ReturnErrorOnFailure(aReader.EnterContainer(containerType1));
     821         1100 :     EventEnvelopeContext context;
     822         1100 :     constexpr bool recurse = false;
     823         1100 :     CHIP_ERROR err         = TLV::Utilities::Iterate(aReader, FetchEventParameters, &context, recurse);
     824         1100 :     if (err == CHIP_END_OF_TLV)
     825              :     {
     826         1100 :         err = CHIP_NO_ERROR;
     827              :     }
     828         1100 :     ReturnErrorOnFailure(err);
     829              : 
     830         1100 :     ReturnErrorOnFailure(aReader.ExitContainer(containerType1));
     831         1100 :     ReturnErrorOnFailure(aReader.ExitContainer(containerType));
     832         1100 :     const PriorityLevel imp = static_cast<PriorityLevel>(context.mPriority);
     833              : 
     834         1100 :     ReclaimEventCtx * const ctx             = static_cast<ReclaimEventCtx *>(apAppData);
     835         1100 :     CircularEventBuffer * const eventBuffer = ctx->mpEventBuffer;
     836         1100 :     if (eventBuffer->IsFinalDestinationForPriority(imp))
     837              :     {
     838          365 :         ChipLogProgress(EventLogging,
     839              :                         "Dropped 1 event from buffer with priority %u and event number  0x" ChipLogFormatX64
     840              :                         " due to overflow: event priority_level: %u",
     841              :                         static_cast<unsigned>(eventBuffer->GetPriority()), ChipLogValueX64(context.mEventNumber),
     842              :                         static_cast<unsigned>(imp));
     843          365 :         ctx->mSpaceNeededForMovedEvent = 0;
     844          365 :         return CHIP_NO_ERROR;
     845              :     }
     846              : 
     847              :     // event is not getting dropped. Note how much space it requires, and return.
     848          735 :     ctx->mSpaceNeededForMovedEvent = aReader.GetLengthRead();
     849          735 :     return CHIP_END_OF_TLV;
     850         1100 : }
     851              : 
     852          344 : void EventManagement::SetScheduledEventInfo(EventNumber & aEventNumber, uint32_t & aInitialWrittenEventBytes) const
     853              : {
     854          344 :     aEventNumber              = mLastEventNumber;
     855          344 :     aInitialWrittenEventBytes = mBytesWritten;
     856          344 : }
     857              : 
     858            0 : CHIP_ERROR EventManagement::GenerateEvent(EventLoggingDelegate * eventPayloadWriter, const EventOptions & options,
     859              :                                           EventNumber & generatedEventNumber)
     860              : {
     861            0 :     return LogEvent(eventPayloadWriter, options, generatedEventNumber);
     862              : }
     863              : 
     864          375 : void CircularEventBuffer::Init(uint8_t * apBuffer, uint32_t aBufferLength, CircularEventBuffer * apPrev,
     865              :                                CircularEventBuffer * apNext, PriorityLevel aPriorityLevel)
     866              : {
     867          375 :     TLVCircularBuffer::Init(apBuffer, aBufferLength);
     868          375 :     mpPrev    = apPrev;
     869          375 :     mpNext    = apNext;
     870          375 :     mPriority = aPriorityLevel;
     871          375 : }
     872              : 
     873         5223 : bool CircularEventBuffer::IsFinalDestinationForPriority(PriorityLevel aPriority) const
     874              : {
     875         5223 :     return !((mpNext != nullptr) && (mpNext->mPriority <= aPriority));
     876              : }
     877              : 
     878              : /**
     879              :  * @brief
     880              :  * TLVCircularBuffer::OnInit can modify the state of the buffer, but we don't want that behavior here.
     881              :  * We want to make sure we don't change our state, and just report the currently-available space.
     882              :  */
     883         1084 : CHIP_ERROR CircularEventBuffer::OnInit(TLV::TLVWriter & writer, uint8_t *& bufStart, uint32_t & bufLen)
     884              : {
     885         1084 :     GetCurrentWritableBuffer(bufStart, bufLen);
     886         1084 :     return CHIP_NO_ERROR;
     887              : }
     888              : 
     889          943 : void CircularEventReader::Init(CircularEventBufferWrapper * apBufWrapper)
     890              : {
     891              :     CircularEventBuffer * prev;
     892              : 
     893          943 :     if (apBufWrapper->mpCurrent == nullptr)
     894            0 :         return;
     895              : 
     896          943 :     TLVReader::Init(*apBufWrapper, apBufWrapper->mpCurrent->DataLength());
     897          943 :     mMaxLen = apBufWrapper->mpCurrent->DataLength();
     898          991 :     for (prev = apBufWrapper->mpCurrent->GetPreviousCircularEventBuffer(); prev != nullptr;
     899           48 :          prev = prev->GetPreviousCircularEventBuffer())
     900              :     {
     901           48 :         CircularEventBufferWrapper bufWrapper;
     902           48 :         bufWrapper.mpCurrent = prev;
     903           48 :         mMaxLen += prev->DataLength();
     904           48 :     }
     905              : }
     906              : 
     907         2933 : CHIP_ERROR CircularEventBufferWrapper::GetNextBuffer(TLVReader & aReader, const uint8_t *& aBufStart, uint32_t & aBufLen)
     908              : {
     909         2933 :     CHIP_ERROR err = CHIP_NO_ERROR;
     910         2933 :     mpCurrent->GetNextBuffer(aReader, aBufStart, aBufLen);
     911         2933 :     SuccessOrExit(err);
     912              : 
     913         2933 :     if ((aBufLen == 0) && (mpCurrent->GetPreviousCircularEventBuffer() != nullptr))
     914              :     {
     915         1814 :         mpCurrent = mpCurrent->GetPreviousCircularEventBuffer();
     916         1814 :         aBufStart = nullptr;
     917         1814 :         err       = GetNextBuffer(aReader, aBufStart, aBufLen);
     918              :     }
     919              : 
     920         1119 : exit:
     921         2933 :     return err;
     922              : }
     923              : 
     924              : } // namespace app
     925              : } // namespace chip
        

Generated by: LCOV version 2.0-1