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