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