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