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 <lib/core/TLVUtilities.h>
25 : #include <lib/support/CodeUtils.h>
26 : #include <lib/support/logging/CHIPLogging.h>
27 :
28 : #include <cassert>
29 : #include <cinttypes>
30 :
31 : using namespace chip::TLV;
32 :
33 : namespace chip {
34 : namespace app {
35 : EventManagement 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 765 : EventManagement & EventManagement::GetInstance()
61 : {
62 765 : return sInstance;
63 : }
64 :
65 : struct ReclaimEventCtx
66 : {
67 : CircularEventBuffer * mpEventBuffer = nullptr;
68 : size_t mSpaceNeededForMovedEvent = 0;
69 : };
70 :
71 : /**
72 : * @brief
73 : * Internal structure for traversing event list.
74 : */
75 : struct CopyAndAdjustDeltaTimeContext
76 : {
77 2163 : CopyAndAdjustDeltaTimeContext(TLVWriter * aWriter, EventLoadOutContext * inContext) : mpWriter(aWriter), mpContext(inContext) {}
78 :
79 : TLV::TLVWriter * mpWriter = nullptr;
80 : EventLoadOutContext * mpContext = nullptr;
81 : };
82 :
83 125 : CHIP_ERROR EventManagement::Init(Messaging::ExchangeManager * apExchangeManager, uint32_t aNumBuffers,
84 : CircularEventBuffer * apCircularEventBuffer,
85 : const LogStorageResources * const apLogStorageResources,
86 : MonotonicallyIncreasingCounter<EventNumber> * apEventNumberCounter,
87 : System::Clock::Milliseconds64 aMonotonicStartupTime, EventReporter * apEventReporter)
88 : {
89 125 : VerifyOrReturnError(apEventReporter != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
90 125 : VerifyOrReturnError(aNumBuffers != 0, CHIP_ERROR_INVALID_ARGUMENT);
91 125 : VerifyOrReturnError(mState == EventManagementStates::Shutdown, CHIP_ERROR_INCORRECT_STATE);
92 :
93 125 : CircularEventBuffer * current = nullptr;
94 125 : CircularEventBuffer * prev = nullptr;
95 125 : CircularEventBuffer * next = nullptr;
96 :
97 125 : mpExchangeMgr = apExchangeManager;
98 :
99 500 : for (uint32_t bufferIndex = 0; bufferIndex < aNumBuffers; bufferIndex++)
100 : {
101 375 : next = (bufferIndex < aNumBuffers - 1) ? &apCircularEventBuffer[bufferIndex + 1] : nullptr;
102 :
103 375 : current = &apCircularEventBuffer[bufferIndex];
104 375 : current->Init(apLogStorageResources[bufferIndex].mpBuffer, apLogStorageResources[bufferIndex].mBufferSize, prev, next,
105 375 : apLogStorageResources[bufferIndex].mPriority);
106 :
107 375 : prev = current;
108 :
109 375 : current->mProcessEvictedElement = nullptr;
110 375 : current->mAppData = nullptr;
111 : }
112 :
113 125 : mpEventNumberCounter = apEventNumberCounter;
114 125 : mLastEventNumber = mpEventNumberCounter->GetValue();
115 :
116 125 : mpEventBuffer = apCircularEventBuffer;
117 125 : mState = EventManagementStates::Idle;
118 125 : mBytesWritten = 0;
119 :
120 125 : mMonotonicStartupTime = aMonotonicStartupTime;
121 :
122 125 : mpEventReporter = apEventReporter;
123 :
124 125 : return CHIP_NO_ERROR;
125 : }
126 :
127 422 : CHIP_ERROR EventManagement::CopyToNextBuffer(CircularEventBuffer * apEventBuffer)
128 : {
129 422 : CircularTLVWriter writer;
130 422 : CircularTLVReader reader;
131 422 : CHIP_ERROR err = CHIP_NO_ERROR;
132 422 : CircularEventBuffer * nextBuffer = apEventBuffer->GetNextCircularEventBuffer();
133 422 : if (nextBuffer == nullptr)
134 : {
135 0 : return CHIP_ERROR_INVALID_ARGUMENT;
136 : }
137 422 : CircularEventBuffer backup = *nextBuffer;
138 :
139 : // Set up the next buffer s.t. it fails if needs to evict an element
140 422 : nextBuffer->mProcessEvictedElement = AlwaysFail;
141 :
142 422 : writer.Init(*nextBuffer);
143 :
144 : // Set up the reader s.t. it is positioned to read the head event
145 422 : reader.Init(*apEventBuffer);
146 :
147 422 : err = reader.Next();
148 422 : SuccessOrExit(err);
149 :
150 422 : err = writer.CopyElement(reader);
151 422 : SuccessOrExit(err);
152 :
153 422 : err = writer.Finalize();
154 422 : SuccessOrExit(err);
155 :
156 422 : ChipLogDetail(EventLogging, "Copy Event to next buffer with priority %u", static_cast<unsigned>(nextBuffer->GetPriority()));
157 0 : exit:
158 422 : if (err != CHIP_NO_ERROR)
159 : {
160 0 : *nextBuffer = backup;
161 : }
162 422 : return err;
163 422 : }
164 :
165 662 : CHIP_ERROR EventManagement::EnsureSpaceInCircularBuffer(size_t aRequiredSpace, PriorityLevel aPriority)
166 : {
167 662 : CHIP_ERROR err = CHIP_NO_ERROR;
168 662 : size_t requiredSpace = aRequiredSpace;
169 662 : CircularEventBuffer * eventBuffer = mpEventBuffer;
170 662 : ReclaimEventCtx ctx;
171 :
172 : // Check that we have this much space in all our event buffers that might
173 : // hold the event. If we do not, that will prevent the event from being
174 : // properly evicted into higher-priority buffers. We want to discover
175 : // this early, so that testing surfaces the need to make those buffers
176 : // larger.
177 1366 : for (auto * currentBuffer = mpEventBuffer; currentBuffer; currentBuffer = currentBuffer->GetNextCircularEventBuffer())
178 : {
179 1366 : VerifyOrExit(requiredSpace <= currentBuffer->GetTotalDataLength(), err = CHIP_ERROR_BUFFER_TOO_SMALL);
180 1366 : if (currentBuffer->IsFinalDestinationForPriority(aPriority))
181 : {
182 662 : break;
183 : }
184 : }
185 :
186 662 : VerifyOrExit(eventBuffer != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
187 :
188 : // check whether we actually need to do anything, exit if we don't
189 662 : VerifyOrExit(requiredSpace > eventBuffer->AvailableDataLength(), err = CHIP_NO_ERROR);
190 :
191 : while (true)
192 : {
193 1884 : if (requiredSpace > eventBuffer->AvailableDataLength())
194 : {
195 1100 : ctx.mpEventBuffer = eventBuffer;
196 1100 : ctx.mSpaceNeededForMovedEvent = 0;
197 :
198 1100 : eventBuffer->mProcessEvictedElement = EvictEvent;
199 1100 : eventBuffer->mAppData = &ctx;
200 1100 : err = eventBuffer->EvictHead();
201 :
202 : // one of two things happened: either the element was evicted immediately if the head's priority is same as current
203 : // buffer(final one), or we figured out how much space we need to evict it into the next buffer, the check happens in
204 : // EvictEvent function
205 :
206 1100 : if (err != CHIP_NO_ERROR)
207 : {
208 735 : VerifyOrExit(ctx.mSpaceNeededForMovedEvent != 0, /* no-op, return err */);
209 735 : VerifyOrExit(eventBuffer->GetNextCircularEventBuffer() != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
210 735 : if (ctx.mSpaceNeededForMovedEvent <= eventBuffer->GetNextCircularEventBuffer()->AvailableDataLength())
211 : {
212 : // we can copy the event outright. copy event and
213 : // subsequently evict head s.t. evicting the head
214 : // element always succeeds.
215 : // Since we're calling CopyElement and we've checked
216 : // that there is space in the next buffer, we don't expect
217 : // this to fail.
218 422 : err = CopyToNextBuffer(eventBuffer);
219 422 : SuccessOrExit(err);
220 : // success; evict head unconditionally
221 422 : eventBuffer->mProcessEvictedElement = nullptr;
222 422 : err = eventBuffer->EvictHead();
223 : // if unconditional eviction failed, this
224 : // means that we have no way of further
225 : // clearing the buffer. fail out and let the
226 : // caller know that we could not honor the
227 : // request
228 422 : SuccessOrExit(err);
229 422 : continue;
230 : }
231 : // we cannot copy event outright. We remember the
232 : // current required space in mRequiredSpaceForEvicted, we note the
233 : // space requirements for the event in the current
234 : // buffer and make that space in the next buffer.
235 313 : eventBuffer->SetRequiredSpaceforEvicted(requiredSpace);
236 313 : eventBuffer = eventBuffer->GetNextCircularEventBuffer();
237 :
238 : // Sanity check: return error here on null event buffer. If
239 : // eventBuffer->mpNext were null, then the `EvictBuffer`
240 : // would have succeeded -- the event was
241 : // already in the final buffer.
242 313 : VerifyOrExit(eventBuffer != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
243 313 : requiredSpace = ctx.mSpaceNeededForMovedEvent;
244 : }
245 : }
246 : else
247 : {
248 : // this branch is only taken when we go back in the buffer chain since we have free/spare enough space in next buffer,
249 : // and need to retry to copy event from current buffer to next buffer, and free space for current buffer
250 784 : if (eventBuffer == mpEventBuffer)
251 471 : break;
252 313 : eventBuffer = eventBuffer->GetPreviousCircularEventBuffer();
253 313 : requiredSpace = eventBuffer->GetRequiredSpaceforEvicted();
254 313 : err = CHIP_NO_ERROR;
255 : }
256 : }
257 :
258 471 : mpEventBuffer->mProcessEvictedElement = nullptr;
259 471 : mpEventBuffer->mAppData = nullptr;
260 :
261 662 : exit:
262 662 : return err;
263 : }
264 :
265 662 : CHIP_ERROR EventManagement::CalculateEventSize(EventLoggingDelegate * apDelegate, const InternalEventOptions * apOptions,
266 : uint32_t & requiredSize)
267 : {
268 662 : System::PacketBufferTLVWriter writer;
269 662 : EventLoadOutContext ctxt = EventLoadOutContext(writer, apOptions->mPriority, GetLastEventNumber());
270 662 : System::PacketBufferHandle buf = System::PacketBufferHandle::New(kMaxEventSizeReserve);
271 662 : if (buf.IsNull())
272 : {
273 0 : return CHIP_ERROR_NO_MEMORY;
274 : }
275 662 : writer.Init(std::move(buf));
276 :
277 662 : ctxt.mCurrentEventNumber = mLastEventNumber;
278 662 : ctxt.mCurrentTime = mLastEventTimestamp;
279 662 : CHIP_ERROR err = ConstructEvent(&ctxt, apDelegate, apOptions);
280 662 : if (err == CHIP_NO_ERROR)
281 : {
282 662 : requiredSize = writer.GetLengthWritten();
283 : }
284 662 : return err;
285 662 : }
286 :
287 1324 : CHIP_ERROR EventManagement::ConstructEvent(EventLoadOutContext * apContext, EventLoggingDelegate * apDelegate,
288 : const InternalEventOptions * apOptions)
289 : {
290 1324 : VerifyOrReturnError(apContext->mCurrentEventNumber >= apContext->mStartingEventNumber, CHIP_NO_ERROR
291 : /* no-op: don't write event, but advance current event Number */);
292 :
293 1324 : VerifyOrReturnError(apOptions != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
294 :
295 1324 : EventReportIB::Builder eventReportBuilder;
296 1324 : ReturnErrorOnFailure(eventReportBuilder.Init(&(apContext->mWriter)));
297 1324 : EventDataIB::Builder & eventDataIBBuilder = eventReportBuilder.CreateEventData();
298 1324 : ReturnErrorOnFailure(eventReportBuilder.GetError());
299 1324 : EventPathIB::Builder & eventPathBuilder = eventDataIBBuilder.CreatePath();
300 1324 : ReturnErrorOnFailure(eventDataIBBuilder.GetError());
301 :
302 1324 : CHIP_ERROR err = eventPathBuilder.Endpoint(apOptions->mPath.mEndpointId)
303 1324 : .Cluster(apOptions->mPath.mClusterId)
304 1324 : .Event(apOptions->mPath.mEventId)
305 1324 : .EndOfEventPathIB();
306 1324 : ReturnErrorOnFailure(err);
307 1324 : eventDataIBBuilder.EventNumber(apContext->mCurrentEventNumber).Priority(chip::to_underlying(apContext->mPriority));
308 1324 : ReturnErrorOnFailure(eventDataIBBuilder.GetError());
309 :
310 1324 : if (apOptions->mTimestamp.IsSystem())
311 : {
312 24 : eventDataIBBuilder.SystemTimestamp(apOptions->mTimestamp.mValue);
313 : }
314 : else
315 : {
316 1300 : eventDataIBBuilder.EpochTimestamp(apOptions->mTimestamp.mValue);
317 : }
318 :
319 1324 : ReturnErrorOnFailure(eventDataIBBuilder.GetError());
320 :
321 : // Callback to write the EventData
322 1324 : ReturnErrorOnFailure(apDelegate->WriteEvent(apContext->mWriter));
323 :
324 : // The fabricIndex profile tag is internal use only for fabric filtering when retrieving event from circular event buffer,
325 : // and would not go on the wire.
326 : // Revisit FabricRemovedCB function should the encoding of fabricIndex change in the future.
327 1324 : if (apOptions->mFabricIndex != kUndefinedFabricIndex)
328 : {
329 8 : apContext->mWriter.Put(TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag), apOptions->mFabricIndex);
330 : }
331 1324 : ReturnErrorOnFailure(eventDataIBBuilder.EndOfEventDataIB());
332 1324 : ReturnErrorOnFailure(eventReportBuilder.EndOfEventReportIB());
333 1324 : ReturnErrorOnFailure(apContext->mWriter.Finalize());
334 1324 : apContext->mFirst = false;
335 1324 : return CHIP_NO_ERROR;
336 : }
337 :
338 124 : void EventManagement::CreateEventManagement(Messaging::ExchangeManager * apExchangeManager, uint32_t aNumBuffers,
339 : CircularEventBuffer * apCircularEventBuffer,
340 : const LogStorageResources * const apLogStorageResources,
341 : MonotonicallyIncreasingCounter<EventNumber> * apEventNumberCounter,
342 : System::Clock::Milliseconds64 aMonotonicStartupTime)
343 : {
344 :
345 124 : sInstance.Init(apExchangeManager, aNumBuffers, apCircularEventBuffer, apLogStorageResources, apEventNumberCounter,
346 124 : aMonotonicStartupTime, &InteractionModelEngine::GetInstance()->GetReportingEngine());
347 124 : }
348 :
349 : /**
350 : * @brief Perform any actions we need to on shutdown.
351 : */
352 124 : void EventManagement::DestroyEventManagement()
353 : {
354 124 : sInstance.mState = EventManagementStates::Shutdown;
355 124 : sInstance.mpEventBuffer = nullptr;
356 124 : sInstance.mpExchangeMgr = nullptr;
357 124 : }
358 :
359 943 : CircularEventBuffer * EventManagement::GetPriorityBuffer(PriorityLevel aPriority) const
360 : {
361 943 : CircularEventBuffer * buf = mpEventBuffer;
362 2757 : while (!buf->IsFinalDestinationForPriority(aPriority))
363 : {
364 1814 : buf = buf->GetNextCircularEventBuffer();
365 1814 : assert(buf != nullptr);
366 : // code guarantees that every PriorityLevel has a buffer destination.
367 : }
368 943 : return buf;
369 : }
370 :
371 10097 : CHIP_ERROR EventManagement::CopyAndAdjustDeltaTime(const TLVReader & aReader, size_t aDepth, void * apContext)
372 : {
373 10097 : CopyAndAdjustDeltaTimeContext * ctx = static_cast<CopyAndAdjustDeltaTimeContext *>(apContext);
374 10097 : TLVReader reader(aReader);
375 :
376 10097 : if (aReader.GetTag() == TLV::ProfileTag(kEventManagementProfile, kFabricIndexTag))
377 : {
378 : // Does not go on the wire.
379 13 : return CHIP_NO_ERROR;
380 : }
381 10105 : if ((aReader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kSystemTimestamp)) && !(ctx->mpContext->mFirst) &&
382 21 : (ctx->mpContext->mCurrentTime.mType == ctx->mpContext->mPreviousTime.mType))
383 : {
384 21 : return ctx->mpWriter->Put(TLV::ContextTag(EventDataIB::Tag::kDeltaSystemTimestamp),
385 42 : ctx->mpContext->mCurrentTime.mValue - ctx->mpContext->mPreviousTime.mValue);
386 : }
387 11236 : if ((aReader.GetTag() == TLV::ContextTag(EventDataIB::Tag::kEpochTimestamp)) && !(ctx->mpContext->mFirst) &&
388 1173 : (ctx->mpContext->mCurrentTime.mType == ctx->mpContext->mPreviousTime.mType))
389 : {
390 0 : return ctx->mpWriter->Put(TLV::ContextTag(EventDataIB::Tag::kDeltaEpochTimestamp),
391 0 : ctx->mpContext->mCurrentTime.mValue - ctx->mpContext->mPreviousTime.mValue);
392 : }
393 :
394 10063 : return ctx->mpWriter->CopyElement(reader);
395 : }
396 :
397 662 : void EventManagement::VendEventNumber()
398 : {
399 662 : CHIP_ERROR err = CHIP_NO_ERROR;
400 : // Now advance the counter.
401 662 : err = mpEventNumberCounter->Advance();
402 662 : if (err != CHIP_NO_ERROR)
403 : {
404 0 : ChipLogError(EventLogging, "%s Advance() failed with %" CHIP_ERROR_FORMAT, __FUNCTION__, err.Format());
405 : }
406 :
407 : // Assign event Number to the buffer's counter's value.
408 662 : mLastEventNumber = mpEventNumberCounter->GetValue();
409 662 : }
410 :
411 666 : CHIP_ERROR EventManagement::LogEvent(EventLoggingDelegate * apDelegate, const EventOptions & aEventOptions,
412 : EventNumber & aEventNumber)
413 : {
414 666 : assertChipStackLockedByCurrentThread();
415 666 : VerifyOrReturnError(mState != EventManagementStates::Shutdown, CHIP_ERROR_INCORRECT_STATE);
416 662 : return LogEventPrivate(apDelegate, aEventOptions, aEventNumber);
417 : }
418 :
419 662 : CHIP_ERROR EventManagement::LogEventPrivate(EventLoggingDelegate * apDelegate, const EventOptions & aEventOptions,
420 : EventNumber & aEventNumber)
421 : {
422 662 : CircularTLVWriter writer;
423 662 : CHIP_ERROR err = CHIP_NO_ERROR;
424 662 : uint32_t requestSize = 0;
425 662 : aEventNumber = 0;
426 662 : CircularTLVWriter checkpoint = writer;
427 662 : EventLoadOutContext ctxt = EventLoadOutContext(writer, aEventOptions.mPriority, mLastEventNumber);
428 662 : InternalEventOptions opts;
429 :
430 662 : Timestamp timestamp;
431 : #if CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
432 : System::Clock::Milliseconds64 utc_time;
433 662 : err = System::SystemClock().GetClock_RealTimeMS(utc_time);
434 662 : if (err == CHIP_NO_ERROR)
435 : {
436 650 : timestamp = Timestamp::Epoch(utc_time);
437 : }
438 : else
439 : #endif // CHIP_DEVICE_CONFIG_EVENT_LOGGING_UTC_TIMESTAMPS
440 : {
441 12 : auto systemTimeMs = System::SystemClock().GetMonotonicMilliseconds64() - mMonotonicStartupTime;
442 12 : timestamp = Timestamp::System(systemTimeMs);
443 : }
444 :
445 662 : opts = InternalEventOptions(timestamp);
446 : // Start the event container (anonymous structure) in the circular buffer
447 662 : writer.Init(*mpEventBuffer);
448 :
449 662 : opts.mPriority = aEventOptions.mPriority;
450 : // Create all event specific data
451 : // Timestamp; encoded as a delta time
452 :
453 662 : opts.mPath = aEventOptions.mPath;
454 662 : opts.mFabricIndex = aEventOptions.mFabricIndex;
455 :
456 662 : ctxt.mCurrentEventNumber = mLastEventNumber;
457 662 : ctxt.mCurrentTime.mValue = mLastEventTimestamp.mValue;
458 :
459 662 : err = CalculateEventSize(apDelegate, &opts, requestSize);
460 662 : SuccessOrExit(err);
461 :
462 : // Ensure we have space in the in-memory logging queues
463 662 : err = EnsureSpaceInCircularBuffer(requestSize, aEventOptions.mPriority);
464 662 : SuccessOrExit(err);
465 :
466 662 : err = ConstructEvent(&ctxt, apDelegate, &opts);
467 662 : SuccessOrExit(err);
468 :
469 662 : mBytesWritten += writer.GetLengthWritten();
470 :
471 662 : exit:
472 662 : if (err != CHIP_NO_ERROR)
473 : {
474 0 : ChipLogError(EventLogging, "Log event with error %" CHIP_ERROR_FORMAT, err.Format());
475 0 : writer = checkpoint;
476 : }
477 : else if (opts.mPriority >= CHIP_CONFIG_EVENT_GLOBAL_PRIORITY)
478 : {
479 662 : aEventNumber = mLastEventNumber;
480 662 : VendEventNumber();
481 662 : mLastEventTimestamp = timestamp;
482 : #if CHIP_CONFIG_EVENT_LOGGING_VERBOSE_DEBUG_LOGS
483 662 : ChipLogDetail(EventLogging,
484 : "LogEvent event number: 0x" ChipLogFormatX64 " priority: %u, endpoint id: 0x%x"
485 : " cluster id: " ChipLogFormatMEI " event id: 0x%" PRIx32 " %s timestamp: 0x" ChipLogFormatX64,
486 : ChipLogValueX64(aEventNumber), static_cast<unsigned>(opts.mPriority), opts.mPath.mEndpointId,
487 : ChipLogValueMEI(opts.mPath.mClusterId), opts.mPath.mEventId,
488 : opts.mTimestamp.mType == Timestamp::Type::kSystem ? "Sys" : "Epoch", ChipLogValueX64(opts.mTimestamp.mValue));
489 : #endif // CHIP_CONFIG_EVENT_LOGGING_VERBOSE_DEBUG_LOGS
490 :
491 662 : err = mpEventReporter->NewEventGenerated(opts.mPath, mBytesWritten);
492 : }
493 :
494 662 : return err;
495 : }
496 :
497 2163 : CHIP_ERROR EventManagement::CopyEvent(const TLVReader & aReader, TLVWriter & aWriter, EventLoadOutContext * apContext)
498 : {
499 2163 : TLVReader reader;
500 : TLVType containerType;
501 : TLVType containerType1;
502 2163 : CopyAndAdjustDeltaTimeContext context(&aWriter, apContext);
503 2163 : CHIP_ERROR err = CHIP_NO_ERROR;
504 :
505 2163 : reader.Init(aReader);
506 2163 : ReturnErrorOnFailure(reader.EnterContainer(containerType));
507 2163 : ReturnErrorOnFailure(aWriter.StartContainer(AnonymousTag(), kTLVType_Structure, containerType));
508 :
509 2149 : ReturnErrorOnFailure(reader.Next());
510 2149 : ReturnErrorOnFailure(reader.EnterContainer(containerType1));
511 2149 : ReturnErrorOnFailure(
512 : aWriter.StartContainer(TLV::ContextTag(EventReportIB::Tag::kEventData), kTLVType_Structure, containerType1));
513 2119 : err = TLV::Utilities::Iterate(reader, CopyAndAdjustDeltaTime, &context, false /*recurse*/);
514 2119 : if (err == CHIP_END_OF_TLV)
515 : {
516 1657 : err = CHIP_NO_ERROR;
517 : }
518 2119 : ReturnErrorOnFailure(err);
519 1657 : ReturnErrorOnFailure(aWriter.EndContainer(containerType1));
520 1652 : ReturnErrorOnFailure(aWriter.EndContainer(containerType));
521 1648 : ReturnErrorOnFailure(aWriter.Finalize());
522 1648 : return CHIP_NO_ERROR;
523 : }
524 :
525 3248 : CHIP_ERROR EventManagement::CheckEventContext(EventLoadOutContext * eventLoadOutContext,
526 : const EventManagement::EventEnvelopeContext & event)
527 : {
528 3248 : if (eventLoadOutContext->mCurrentEventNumber < eventLoadOutContext->mStartingEventNumber)
529 : {
530 1032 : return CHIP_ERROR_UNEXPECTED_EVENT;
531 : }
532 :
533 2251 : if (event.mFabricIndex.HasValue() &&
534 35 : (event.mFabricIndex.Value() == kUndefinedFabricIndex ||
535 28 : eventLoadOutContext->mSubjectDescriptor.fabricIndex != event.mFabricIndex.Value()))
536 : {
537 22 : return CHIP_ERROR_UNEXPECTED_EVENT;
538 : }
539 :
540 2194 : ConcreteEventPath path(event.mEndpointId, event.mClusterId, event.mEventId);
541 2194 : CHIP_ERROR ret = CHIP_ERROR_UNEXPECTED_EVENT;
542 :
543 2242 : for (auto * interestedPath = eventLoadOutContext->mpInterestedEventPaths; interestedPath != nullptr;
544 48 : interestedPath = interestedPath->mpNext)
545 : {
546 2217 : if (interestedPath->mValue.IsEventPathSupersetOf(path))
547 : {
548 2169 : ret = CHIP_NO_ERROR;
549 2169 : break;
550 : }
551 : }
552 :
553 2194 : ReturnErrorOnFailure(ret);
554 :
555 : DataModel::EventEntry eventInfo;
556 2169 : ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->GetDataModelProvider()->EventInfo(path, eventInfo));
557 :
558 2169 : Access::RequestPath requestPath{ .cluster = event.mClusterId,
559 2169 : .endpoint = event.mEndpointId,
560 : .requestType = Access::RequestType::kEventReadRequest,
561 2169 : .entityId = event.mEventId };
562 : CHIP_ERROR accessControlError =
563 2169 : Access::GetAccessControl().Check(eventLoadOutContext->mSubjectDescriptor, requestPath, eventInfo.readPrivilege);
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 : }
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 : }
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
|